framework performance linq entity-framework asp.net-mvc-2 linq-to-entities

performance - ¿Cuántas Include puedo usar en ObjectSet en EntityFramework para conservar el rendimiento?



linq entity framework c# (5)

Estoy usando la siguiente consulta LINQ para mi página de perfil:

var userData = from u in db.Users .Include("UserSkills.Skill") .Include("UserIdeas.IdeaThings") .Include("UserInterests.Interest") .Include("UserMessengers.Messenger") .Include("UserFriends.User.UserSkills.Skill") .Include("UserFriends1.User1.UserSkills.Skill") .Include("UserFriends.User.UserIdeas") .Include("UserFriends1.User1.UserIdeas") where u.UserId == userId select u;

Tiene un gráfico de objeto largo y usa muchos includes. Se está ejecutando perfecto en este momento, pero cuando el sitio tiene muchos usuarios, ¿afectará mucho el rendimiento?

¿Debo hacerlo de alguna otra manera?


Le recomendaría que realice pruebas de carga y mida el rendimiento del sitio bajo presión. Si realiza consultas complejas en cada solicitud, puede considerar almacenar en caché algunos resultados.


Puede mejorar el rendimiento de muchos includes creando 2 o más solicitudes de datos pequeños desde la base de datos, como se muestra a continuación.

De acuerdo con mi experiencia, solo se puede dar un máximo de 2 por cada consulta, como a continuación. Más que eso dará un rendimiento realmente malo.

var userData = from u in db.Users .Include("UserSkills.Skill") .Include("UserIdeas.IdeaThings") .FirstOrDefault(); userData = from u in db.Users .Include("UserFriends.User.UserSkills.Skill") .Include("UserFriends1.User1.UserSkills.Skill") .FirstOrDefault();

Arriba traerá un pequeño conjunto de datos de la base de datos al usar más viajes a la base de datos.

He escrito una publicación en el blog sobre esto usando mi propia experiencia. Está Here

Espero que esto te ayude.


Sí lo hará. Evite usar Incluir si expande varias filas de detalles en una fila de tabla maestra.

Creo que EF convierte la consulta en una unión grande en lugar de varias consultas. Por lo tanto, terminará duplicando los datos de su tabla maestra en cada fila de la tabla de detalles.

Por ejemplo: Maestro -> Detalles. Decir, el maestro tiene 100 filas, Detalles tiene 5000 filas (50 para cada maestro).

Si carga los detalles de forma perezosa, devuelve 100 filas (tamaño: maestro) + 5000 filas (tamaño: detalles).

Si usa .Include ("Detalles"), devuelve 5000 filas (tamaño: maestro + detalles). Esencialmente, la porción maestra se duplica más de 50 veces.

Se multiplica hacia arriba si incluye varias tablas.

Verifica el SQL generado por EF.


Una consulta con includes arroja un único conjunto de resultados y el número de inclusiones afecta la forma en que se transfiere el gran conjunto de datos desde el servidor de la base de datos al servidor web. Ejemplo:

Supongamos que tenemos una entidad Customer (Id, Name, Address) y una Order (Id, CustomerId, Date) entidad Order (Id, CustomerId, Date) . Ahora queremos consultar a un cliente con sus pedidos:

var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == 1);

El conjunto de datos resultante tendrá la siguiente estructura:

Id | Name | Address | OrderId | CustomerId | Date --------------------------------------------------- 1 | A | XYZ | 1 | 1 | 1.1. 1 | A | XYZ | 2 | 1 | 2.1.

Significa que los datos de Cutomers se repiten para cada Order . Ahora permitamos extender el ejemplo con otras entidades: ''OrderLine (Id, OrderId, ProductId, Quantity) and Product (Id, Name)''. Ahora queremos consultar a un cliente con sus pedidos, líneas de pedido y productos:

var customer = context.Customers .Include("Orders.OrderLines.Product") .SingleOrDefault(c => c.Id == 1);

El conjunto de datos resultante tendrá la siguiente estructura:

Id | Name | Address | OrderId | CustomerId | Date | OrderLineId | LOrderId | LProductId | Quantity | ProductId | ProductName ------------------------------------------------------------------------------------------------------------------------------ 1 | A | XYZ | 1 | 1 | 1.1. | 1 | 1 | 1 | 5 | 1 | AA 1 | A | XYZ | 1 | 1 | 1.1. | 2 | 1 | 2 | 2 | 2 | BB 1 | A | XYZ | 2 | 1 | 2.1. | 3 | 2 | 1 | 4 | 1 | AA 1 | A | XYZ | 2 | 1 | 2.1. | 4 | 2 | 3 | 6 | 3 | CC

Como puede ver, los datos se duplican bastante. Normalmente cada uno incluye una propiedad de navegación de referencia ( Product en el ejemplo) agregará nuevas columnas y cada una incluye una propiedad de navegación de colección ( Orders y OrderLines Orders en el ejemplo) agregará nuevas columnas y duplicará las filas ya creadas para cada fila en la colección incluida .

Significa que su ejemplo puede tener fácilmente cientos de columnas y miles de filas, que es una gran cantidad de datos para transferir. El enfoque correcto es crear pruebas de rendimiento y si el resultado no satisface sus expectativas, puede modificar su consulta y cargar las propiedades de navegación por separado mediante sus propias consultas o mediante el método LoadProperty .

Ejemplo de consultas separadas:

var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == 1); var orderLines = context.OrderLines .Include("Product") .Where(l => l.Order.Customer.Id == 1) .ToList();

Ejemplo de LoadProperty :

var customer = context.Customers .SingleOrDefault(c => c.Id == 1); context.LoadProperty(customer, c => c.Orders);

Además, siempre debe cargar solo los datos que realmente necesita.

Editar: Acabo de crear una propuesta en Data UserVoice para admitir una estrategia de carga adicional ansiosa donde los datos cargados ansiosos se pasarán en un conjunto de resultados adicional (creado por consulta separada dentro de la misma base de datos ida y vuelta). Si le parece interesante esta mejora, no olvide votar a favor de la propuesta.


El resultado de la inclusión puede cambiar: depende de la entidad que llama al método de inclusión.

Como el ejemplo propuesto por Ladislav Mrnka, supongamos que tenemos una entidad

Cliente (Id, Nombre, Dirección)

ese mapa a esta tabla:

Id | Name | Address ----------------------- C1 | Paul | XYZ

y un pedido de entidad (Id, CustomerId, Total)

ese mapa a esta tabla:

Id | CustomerId | Total ----------------------- O1 | C1 | 10.00 O2 | C1 | 13.00

La relación es un cliente para muchas órdenes

Ejemplo 1: Cliente => Pedidos

var customer = context.Customers .Include("Orders") .SingleOrDefault(c => c.Id == "C1");

Linq se traducirá en una consulta SQL muy compleja.

En este caso, la consulta generará dos registros y se replicará la información sobre el cliente.

Customer.Id | Customer.Name | Order.Id | Order.Total ----------------------------------------------------------- C1 | Paul | O1 | 10.00 C1 | Paul | O2 | 13.00

Ejemplo 2: pedido => cliente

var order = context.Orders .Include("Customers") .SingleOrDefault(c => c.Id == "O1");

Linq se traducirá en una simple combinación sql.

En este caso, la consulta producirá solo un registro sin duplicación de información:

Order.Id | Order.Total | Customer.Id | Customer.Name ----------------------------------------------------------- O1 | 10.00 | C1 | Paul