在我的项目中,我正在使用EntityFramework 4来处理数据。我通过简单的查询发现了可怕的性能问题。当我在EF4生成的SQL查询上查看分析器时,我感到很震惊。
我的实体数据模型中有一些表:
看起来很简单。我正在尝试从指定类别中选择所有相关导航属性的所有产品。
我写了这个LINQ查询:
ObjectSet<ProductItem> objectSet = ...;
int categoryId = ...;
var res = from pi in objectSet.Include("Product").Include("Inventory").Include("Inventory.Storage")
where pi.Product.CategoryId == categoryId
select pi;
EF生成了这个SQL查询:
SELECT [Project1].[pintId1] AS [pintId],
[Project1].[pintId] AS [pintId1],
[Project1].[intProductId] AS [intProductId],
[Project1].[nvcSupplier] AS [nvcSupplier],
[Project1].[ nvcArticle] AS [ nvcArticle],
[Project1].[nvcBarcode] AS [nvcBarcode],
[Project1].[bIsActive] AS [bIsActive],
[Project1].[dtDeleted] AS [dtDeleted],
[Project1].[pintId2] AS [pintId2],
[Project1].[nvcName] AS [nvcName],
[Project1].[intCategoryId] AS [intCategoryId],
[Project1].[ncProductType] AS [ncProductType],
[Project1].[C1] AS [C1],
[Project1].[pintId3] AS [pintId3],
[Project1].[intProductItemId] AS [intProductItemId],
[Project1].[intStorageId] AS [intStorageId],
[Project1].[dAmount] AS [dAmount],
[Project1].[mPrice] AS [mPrice],
[Project1].[dtModified] AS [dtModified],
[Project1].[pintId4] AS [pintId4],
[Project1].[nvcName1] AS [nvcName1],
[Project1].[bIsDefault] AS [bIsDefault]
FROM (SELECT [Extent1].[pintId] AS [pintId],
[Extent1].[intProductId] AS [intProductId],
[Extent1].[nvcSupplier] AS [nvcSupplier],
[Extent1].[ nvcArticle] AS [ nvcArticle],
[Extent1].[nvcBarcode] AS [nvcBarcode],
[Extent1].[bIsActive] AS [bIsActive],
[Extent1].[dtDeleted] AS [dtDeleted],
[Extent2].[pintId] AS [pintId1],
[Extent3].[pintId] AS [pintId2],
[Extent3].[nvcName] AS [nvcName],
[Extent3].[intCategoryId] AS [intCategoryId],
[Extent3].[ncProductType] AS [ncProductType],
[Join3].[pintId1] AS [pintId3],
[Join3].[intProductItemId] AS [intProductItemId],
[Join3].[intStorageId] AS [intStorageId],
[Join3].[dAmount] AS [dAmount],
[Join3].[mPrice] AS [mPrice],
[Join3].[dtModified] AS [dtModified],
[Join3].[pintId2] AS [pintId4],
[Join3].[nvcName] AS [nvcName1],
[Join3].[bIsDefault] AS [bIsDefault],
CASE
WHEN ([Join3].[pintId1] IS NULL) THEN CAST(NULL AS int)
ELSE 1
END AS [C1]
FROM [ProductItem] AS [Extent1]
INNER JOIN [Product] AS [Extent2]
ON [Extent1].[intProductId] = [Extent2].[pintId]
LEFT OUTER JOIN [Product] AS [Extent3]
ON [Extent1].[intProductId] = [Extent3].[pintId]
LEFT OUTER JOIN (SELECT [Extent4].[pintId] AS [pintId1],
[Extent4].[intProductItemId] AS [intProductItemId],
[Extent4].[intStorageId] AS [intStorageId],
[Extent4].[dAmount] AS [dAmount],
[Extent4].[mPrice] AS [mPrice],
[Extent4].[dtModified] AS [dtModified],
[Extent5].[pintId] AS [pintId2],
[Extent5].[nvcName] AS [nvcName],
[Extent5].[bIsDefault] AS [bIsDefault]
FROM [Inventory] AS [Extent4]
INNER JOIN [Storage] AS [Extent5]
ON [Extent4].[intStorageId] = [Extent5].[pintId]) AS [Join3]
ON [Extent1].[pintId] = [Join3].[intProductItemId]
WHERE [Extent2].[intCategoryId] = 8 /* @p__linq__0 */) AS [Project1]
ORDER BY [Project1].[pintId1] ASC,
[Project1].[pintId] ASC,
[Project1].[pintId2] ASC,
[Project1].[C1] ASC
对于数据库中的7000条记录和指定类别中的~1000条记录,此查询的执行时间ID大约为10秒。如果看这个就不足为奇了:
FROM [ProductItem] AS [Extent1]
INNER JOIN [Product] AS [Extent2]
ON [Extent1].[intProductId] = [Extent2].[pintId]
LEFT OUTER JOIN [Product] AS [Extent3]
ON [Extent1].[intProductId] = [Extent3].[pintId]
***LEFT OUTER JOIN (SELECT ....***
嵌套选择加入...可怕......我试图更改LINQ查询,但是我得到了相同的SQL查询输出。
使用存储过程的解决方案对我来说是不可接受的,因为我正在使用SQL Compact数据库。
答案 0 :(得分:7)
你正在做Include("Product").Include("Inventory").Include("Inventory.Storage")
,你想知道为什么要提取这么多记录,为什么会看到如此大的SQL查询呢?请确保您了解Include
方法的含义。如果您想要更简单的查询,请使用以下内容:
var res =
from pi in objectSet
where pi.Product.CategoryId == categoryId
select pi;
但请注意,这可能会延迟加载Products
,Inventories
和Storages
,这会导致在迭代这些子集合时发送更多查询。
答案 1 :(得分:0)
我认为问题在于Storage元素中的Inventory集合。您的查询会将选定的Product,ProductItem和Inventory项目限制为指定的CategoryId项目。但是,为了填充Storage元素的Inventory集合,查询还必须返回使用相同StorageId的所有Inventory行(然后返回那些额外Inventory目录的所有相应ProductItem和Product行。
我首先从Storage元素中删除Inventory集合,或者删除相应的include。