2010-09-21 9 views
9

En mi proyecto estoy usando EntityFramework 4 para trabajar con datos. Encontré problemas de rendimiento horribles con una simple consulta. Cuando miré el generador de perfiles en una consulta sql, generada por EF4, me sorprendió.Consultas de Linq en Entity Framework 4. Horrible rendimiento

que tienen algunas mesas en mi modelo de datos entidad:

Data Model

Se ve bastante simple. Intento seleccionar todos los artículos del producto de la categoría especificada con todas las propiedades de navegación relacionadas.

escribí esta consulta 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 genera esta consulta 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 

Para 7000 registros en la base de datos y ~ 1000 récord en la categoría especificada de tiempo de ejecución de esta consulta Identificación alrededor de 10 segundos . No es sorprendente que mira esto:

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 ....*** 

anidada seleccionar en unirse a ... horrible ... He intentado cambiar consulta LINQ, pero consigo misma consulta SQL emite.

Una solución que utiliza procedimientos almacenados no es aceptable para mí, porque estoy usando la base de datos SQL Compact.

+3

Tu inglés no es tan malo :) Pregunta bien formada también. +1 – Aren

+1

Puede usar http://imgur.com/ para compartir imágenes. – Steven

+2

¿Qué pasa con los Incluye? ¿Por qué no simplemente _from pi en objectSet donde pi.Product.CategoryId == categoryId select pi_? –

Respuesta

7

Usted está haciendo Include("Product").Include("Inventory").Include("Inventory.Storage") y se está preguntando por qué se obtienen tantos registros y por qué para ver una consulta SQL tan grande. Asegúrese de comprender de qué se trata el método Include. Si desea una consulta simple, por favor utilice la siguiente:

var res = 
    from pi in objectSet 
    where pi.Product.CategoryId == categoryId 
    select pi; 

Tenga en cuenta sin embargo que esto sea posible carga Products, Inventories y Storages perezosamente, lo que podría causar muchos más consultas que se enviará cuando iterar sobre esas colecciones sub .

+0

+1 buen punto: con el Producto: ProductItem (1: *) y ProductItem: Inventory (1: *), un solo Producto lo hará carga un montón de datos extra (posiblemente innecesarios) ... no es de extrañar que sea lento ... –

0

Estoy pensando que el problema es con la colección de Inventario en el elemento de Almacenamiento. Su consulta limitará los artículos de Producto, Producto e Inventario seleccionados a aquellos para la Categoría ID especificada. Sin embargo, para llenar la colección de Inventario del elemento de Almacenamiento, la consulta también debe devolver todas las filas de Inventario que usen los mismos Id. De Almacenamiento (y luego todas las filas ProductItem y Producto correspondientes para esos registros de Inventario adicionales.

I Comenzaremos eliminando la colección de Inventario del elemento de Almacenamiento o eliminando la inclusión correspondiente.

Cuestiones relacionadas