1
Entity FrameworkでGROUP BY
およびWHERE
に深刻なパフォーマンスの問題があります。ここでEntity Frameworkで条件付き高速GroupByクエリを作成する方法
はNorthwind Databaseのためのクエリの例です:
from order in Orders
join detail in OrderDetails on order.OrderID equals detail.OrderID
group detail by order.OrderDate into dateGroup
select new
{
dateGroup.Key,
Foo = dateGroup.Where(e => e.ProductID > 20).Sum(e => (decimal?)e.UnitPrice) ?? 0,
Bar = dateGroup.Where(e => e.ProductID > 40).Sum(e => (decimal?)e.UnitPrice) ?? 0,
Baz = dateGroup.Where(e => e.ProductID > 60).Sum(e => (decimal?)e.UnitPrice) ?? 0
}
これは、次のSQLを生成:あなたは、Foo
、Bar
とBaz
を見ることができるように
-- Region Parameters
DECLARE @p0 Int = 20
DECLARE @p1 Decimal(5,4) = 0
DECLARE @p2 Int = 40
DECLARE @p3 Decimal(5,4) = 0
DECLARE @p4 Int = 60
DECLARE @p5 Decimal(5,4) = 0
-- EndRegion
SELECT [t2].[OrderDate] AS [Key], COALESCE((
SELECT SUM([t5].[value])
FROM (
SELECT [t4].[UnitPrice] AS [value], [t4].[ProductID], [t3].[OrderDate]
FROM [Orders] AS [t3]
INNER JOIN [Order Details] AS [t4] ON [t3].[OrderID] = [t4].[OrderID]
) AS [t5]
WHERE ([t5].[ProductID] > @p0) AND ((([t2].[OrderDate] IS NULL) AND ([t5].[OrderDate] IS NULL)) OR (([t2].[OrderDate] IS NOT NULL) AND ([t5].[OrderDate] IS NOT NULL) AND ([t2].[OrderDate] = [t5].[OrderDate])))
),@p1) AS [Foo], COALESCE((
SELECT SUM([t8].[value])
FROM (
SELECT [t7].[UnitPrice] AS [value], [t7].[ProductID], [t6].[OrderDate]
FROM [Orders] AS [t6]
INNER JOIN [Order Details] AS [t7] ON [t6].[OrderID] = [t7].[OrderID]
) AS [t8]
WHERE ([t8].[ProductID] > @p2) AND ((([t2].[OrderDate] IS NULL) AND ([t8].[OrderDate] IS NULL)) OR (([t2].[OrderDate] IS NOT NULL) AND ([t8].[OrderDate] IS NOT NULL) AND ([t2].[OrderDate] = [t8].[OrderDate])))
),@p3) AS [Bar], COALESCE((
SELECT SUM([t11].[value])
FROM (
SELECT [t10].[UnitPrice] AS [value], [t10].[ProductID], [t9].[OrderDate]
FROM [Orders] AS [t9]
INNER JOIN [Order Details] AS [t10] ON [t9].[OrderID] = [t10].[OrderID]
) AS [t11]
WHERE ([t11].[ProductID] > @p4) AND ((([t2].[OrderDate] IS NULL) AND ([t11].[OrderDate] IS NULL)) OR (([t2].[OrderDate] IS NOT NULL) AND ([t11].[OrderDate] IS NOT NULL) AND ([t2].[OrderDate] = [t11].[OrderDate])))
),@p5) AS [Baz]
FROM (
SELECT [t0].[OrderDate]
FROM [Orders] AS [t0]
INNER JOIN [Order Details] AS [t1] ON [t0].[OrderID] = [t1].[OrderID]
GROUP BY [t0].[OrderDate]
) AS [t2]
を別々のサブクエリとして実行されます。各サブクエリselect
およびjoin
が再び発生します。もっとこのようなものです
何か:何とかそれイスト
SELECT
Orders.OrderDate,
SUM(
CASE
WHEN [Order Details].ProductID > 20
THEN [Order Details].UnitPrice
ELSE 0
END
) as Foo,
SUM(
CASE
WHEN [Order Details].ProductID > 40
THEN [Order Details].UnitPrice
ELSE 0
END
) as Bar,
SUM(
CASE
WHEN [Order Details].ProductID > 60
THEN [Order Details].UnitPrice
ELSE 0
END
) as Baz
FROM Orders
JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID
GROUP BY Orders.OrderDate
可能性はctx.Database.SqlQuery<T>
を使用せずに、基本的なLINQプロバイダは、このシナリオのためのより良いSQLを生成させるには?
実際のシナリオでは、7つの結合、ネストされたグループ、さらにはそれ以上の条件について話しています。 EFは180秒、SQLは3秒必要です。
この場合、解決策*は、EFを使用するのではなくクエリを実行するためのストアドプロシージャを作成する*でしょう。 – ChrisF
このケースでは、私はおそらく私自身のstoreprocedureを作成します。 –
これはStackOverflowの人たちが[Dapper](https://github.com/StackExchange/dapper-dot-net)を書いた理由です。 – juharr