una tipo puede framework entidad consultas consulta construir complejo c# entity-framework azure entity-framework-6 azure-sql-database

c# - tipo - Entity Framework: ¿cómo evitar la recompilación de consultas?



consultas entity framework c# (1)

Estoy trabajando en la optimización de nuestro código de Entity Framework, y actualmente estoy enfrentando un problema que no estoy seguro de cómo resolverlo.

Estamos utilizando Azure SQL + Code-First Entity Framework 6.1.3 + Asp.net Web Api v2 . Endpoint está alojado en la nube y lo estoy usando para probar.

Tengo una acción API, que se utiliza para obtener datos filtrados, ordenados y paginados. Aquí hay un código simplificado de lo que hago con los datos:

var entities = DbContext.Services .Include(q => q.Consumer.Building.Address.Country) .Include(q => q.Consumer.Building.Address.State); entities = entities.OrderBy(x => x.Consumer.RegisteredAt); entities = entities.Where(x => x.IsDeleted == false); entities = entities.Where(x => userId.HasValue ? x.Owner.Id == userId ? true); //this part comes from deep internals, so I cannot change it quickly var page = entities = entities.Skip(skip).Take(take).ToList(); var count = entities.Count(); var dtoPage = Mapper.Map<IEnumerable<ServiceDto>>(page); return Page<ServiceDto>(dtoPage, count);

Por lo tanto, el código no hace nada excepcional, no usa la cláusula IN , etc., solo filtro simple, clasificación y paginación.

El problema: Llamar a este método tiene un tiempo de ejecución inestable. Utilicé una secuencia de comandos simple para llamar al punto final de API que llama a este código con diferentes parámetros: obtiene páginas 0..5 en consecuencia, 200 veces, una tras otra. Para cada llamada (excepto la primera) esperaba que la llamada durara menos de 300 ms. PERO: a partir de 1200 llamadas en general, 36 tiempos de llamadas excedieron 1 segundo, al igual que la consulta se volvió a compilar de nuevo durante este tiempo. El tiempo promedio para las llamadas fue de 250 ms , pero se incrementó a veces a 1000 ms, es 4 veces la diferencia.

Comportamiento común para las pruebas es:

  1. La primera consulta es lenta

  2. La segunda consulta es más rápida, pero aún más lenta que el resto

  3. Las consultas de reposo son bastante estables y rápidas, a excepción de algunos picos de vez en cuando.

Nadie usó el entorno de prueba, excepto yo, por lo que no es un problema de carga, puedo reproducirlo en cualquier entorno, incluso en una PC local rápida: i5 + 8 gb RAM + SSD.

También incluso pequeños retrasos entre pruebas

Entonces mi pregunta en resumen es: ¿de qué viene este problema?

  1. ¿Es esto realmente un tema de recompilación? Si no, ¿cuál es la posible fuente del problema?
  2. ¿Hay algún documento sobre la invalidación de caché de consultas para Entity Framework 6?
  3. ¿Hay alguna manera de mantener una consulta en la memoria caché durante más tiempo, de modo que si consulto el método ahora y en 30 minutos, no tendría que volver a compilarlo?

¿Es esto realmente un problema de recompilación?

No creo que sea un problema de recompilación. Pero puedes mitigar las recompilaciones pasando lambdas en tus llamadas de Skip y Take . Ver 4.2 Uso de funciones que producen consultas con constantes

si no, ¿cuál es la posible fuente del problema?

AFAIK SqlAzure es un entorno compartido. Puede ser la causa de tu problema.

¿Hay algún documento sobre la invalidación de caché de consultas para Entity Framework 6? ¿Hay alguna manera de mantener una consulta en la memoria caché durante más tiempo, de modo que si consulto el método ahora y en 30 minutos, no tendría que volver a compilarlo?

La consulta de Entity Framework permanecerá en la memoria siempre que el AppDomain, el plan de consulta sql permanecerá en la memoria del servidor Sql siempre que el servidor no necesite memoria. El Skip y Take with lambdas también ayudará en ese asunto. Ver en la misma página:

"In EF6 these methods have a lambda overload that effectively makes the cached query plan reusable because EF can capture variables passed to these methods and translate them to SQLparameters. This also helps keep the cache cleaner since otherwise each query with a different constant for Skip and Take would get its own query plan cache entry"