Solución de optimización del rendimiento de EFCore: optimizar la consulta

El rendimiento de la base de datos es un tema amplio y complejo que involucra toda la pila de componentes: base de datos, red, controladores de base de datos y capas de acceso a datos (como EF Core). Aunque las capas de alto nivel y O/RM, como EF Core, simplifican enormemente el desarrollo de aplicaciones y mejoran la capacidad de mantenimiento, a veces pueden ser opacas y ocultar detalles internos críticos para el rendimiento, como el SQL que se ejecuta.

Algunos problemas de rendimiento criticados siempre han sido un tema candente. La situación real puede no ser un rendimiento deficiente, sino cómo evitar trampas y hoyos que afectan el rendimiento.

1. Utilice los índices correctamente

El principal determinante de si una consulta se ejecutará rápidamente es si utiliza índices en los lugares correctos: las bases de datos se utilizan a menudo para contener grandes cantidades de datos, y las consultas que atraviesan tablas enteras suelen ser la fuente de graves problemas de rendimiento.

// 在开始时匹配,使用索引 (SQL Server)
var posts1 = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
// 在末尾匹配,不使用索引
var posts2 = context.Posts.Where(p => p.Title.EndsWith("A")).ToList();
2. Consulta solo los atributos requeridos

EF Core hace que sea muy fácil buscar instancias de entidades y usarlas en el código. Sin embargo, la consulta de instancias de entidades con frecuencia puede extraer más datos de la base de datos de los necesarios. Considere la siguiente situación:

foreach (var blog in context.Blogs)
{
 Console.WriteLine("Blog: " + blog.Url);
}

SQL

SELECT [b].[BlogId], [b].[CreationDate], [b].[Name], [b].[Rating], [b].[Url]...
FROM [Blogs]

La forma de optimizar esto es Selectdecirle a EF qué columnas buscar usando:

foreach (var blogName in context.Blogs.Select(b => b.Url))
{
  Console.WriteLine("Blog: " + blogName);
}

SQL

SELECT [b].[Url]
FROM [Blogs] AS [b]

Este enfoque es excelente para consultas de solo lectura, pero si necesita actualizar el Blog obtenido, las cosas se complican porque el seguimiento de cambios de EF solo funciona en instancias de entidad.

3. Limite el tamaño del conjunto de resultados

El número de filas devueltas depende de los datos reales de la base de datos, por lo que es imposible saber cuántos datos se cargarán desde la base de datos, cuánta memoria ocuparán los resultados y cuándo se procesarán esos resultados (por ejemplo, enviándolos). la red al navegador del usuario) agregará extra La cantidad de carga generada.

var blogs25 = context.Posts
 .Where(p => p.Title.StartsWith("A"))
 .Take(5)
 .ToList();
4. Priorizar el uso de métodos asincrónicos Async

EF Core proporciona muchos métodos asincrónicos como xxxAsync; se recomienda utilizar estos métodos para mejorar el rendimiento y reducir demoras y esperas innecesarias.

5. Desactivar el seguimiento del estado

El comportamiento de seguimiento determina si EF Core mantiene información instantánea sobre instancias de entidad en su rastreador de cambios. Si se realiza un seguimiento de una entidad, cualquier cambio detectado en esa entidad se guarda permanentemente en la base de datos durante SaveChanges(). Las consultas sin seguimiento son útiles cuando decide simplemente consultar los datos, no cambiarlos. Las consultas sin seguimiento se ejecutan más rápido porque no es necesario establecer información de seguimiento instantánea para las entidades que realizan la consulta. Se deben utilizar consultas sin seguimiento con preferencia si no es necesario actualizar las entidades recuperadas de la base de datos.

//单体查询关闭:
AsNoTracking()
//整个上下文关闭:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
6. Desactive la sincronización del estado de DetectChanges

Al consultar datos de la base de datos, el contexto captura una instantánea de cada atributo de la entidad (valor de la base de datos, valor original, valor actual), y cuando se llama a SaveChanges, se llama automáticamente internamente al método DetectChanges, que escanea todas las entidades en el contexto, y compare el valor del atributo actual con el valor del atributo original almacenado en la instantánea. Si el valor del atributo encontrado ha cambiado, EF interactuará con la base de datos para actualizar los datos.

Hace que los métodos DetectChanges se llamen automáticamente: Buscar, Local, Eliminar, Agregar, Actualizar, Adjuntar, GuardarChanges y

Entrada, etc.

Sin embargo, el estado de sincronización automática se llamará con frecuencia y la sincronización automática de los métodos anteriores se puede desactivar manualmente. Cuando se modifican los datos, se realiza una sincronización manual una sola vez.

context.ChangeTracker.AutoDetectChangesEnabled = false;
//执行操作后手动同步状态
context.ChangeTracker.DetectChanges();
7. Utilice EF.Functions.xxx para consultas difusas

EF Core admite el uso de los métodos StartsWith, contains y EndsWith para consultas difusas. Estos métodos se traducen en declaraciones LIKE, pero para mejorar el rendimiento, también se proporciona un método EF.Functions.Like. La declaración SQL generada por este método tiene mejor interpretación.

var result= context.Blogs.Where(b => EF.Functions.Like(b.BlogName, "%xcode%"))
8. Paginación eficiente

La paginación se refiere a recuperar resultados en páginas, en lugar de todos a la vez; esto generalmente se hace para conjuntos de resultados grandes, donde se muestra una interfaz de usuario que permite al usuario navegar a la página de resultados siguiente o anterior.

9. Almacenamiento en búfer y transmisión

El almacenamiento en búfer significa cargar todos los resultados de la consulta en la memoria, mientras que la transmisión significa que EF entrega los resultados a la aplicación uno a la vez, sin mantener nunca todo el conjunto de resultados en la memoria. En principio, los requisitos de memoria para consultas de transmisión son fijos: los requisitos de memoria son los mismos ya sea que la consulta devuelva 1 fila o 1000 filas. Por otro lado, cuantas más filas se devuelvan, más memoria se necesitará para almacenar en el buffer la consulta. Para consultas que producen conjuntos de resultados grandes, este puede ser un factor de rendimiento importante.

// oList和ToArray会导致整个结果集被缓冲:
var blogsList = context.Posts.Where(p => p.Title.StartsWith("A")).ToList();
var blogsArray = context.Posts.Where(p => p.Title.StartsWith("A")).ToArray();
​
// foreach流式,每次处理一行:
foreach (var blog in context.Posts.Where(p => p.Title.StartsWith("A")))
{
 // ...
}

Si su consulta arroja solo unos pocos resultados, probablemente no necesite preocuparse por esto. Sin embargo, si el número de filas que puede devolver una consulta es muy alto, puede valer la pena considerar la transmisión en lugar del almacenamiento en búfer.

10. Precargar entidades relacionadas

Existe un problema clásico en ORM, es decir, el problema N+1, que generalmente aparece en consultas de uno a muchos. El problema N+1 surge de esta manera: consulta la tabla principal una vez para obtener N registros y consulta la subtabla asociada en función de los N registros, y necesita N veces. En el caso de una gran cantidad de datos, consume mucho rendimiento de la ruta de datos.

La carga ansiosa en EFCore significa cargar datos asociados de la base de datos como parte de la consulta inicial para que todos los datos requeridos se puedan recuperar en un solo viaje.

Utilice Includeel método para especificar los datos asociados que se incluirán en los resultados de la consulta:

var blogs = context.Blogs
 .Include(blog => blog.Posts)
 .ToList();

Cualquier tecnología tiene dos caras: la ventaja de utilizar el modo N+1 es que parte de los datos se pueden almacenar en caché por separado.

11. Utilice SQL sin formato

En algunos casos, existe un SQL más optimizado para su consulta y EF no puede generar dicho SQL. En estos casos, escribir SQL manualmente puede mejorar significativamente el rendimiento, por ejemplo a través de FromSqlRaw .

Supongo que te gusta

Origin blog.csdn.net/gcf10080353/article/details/131716268
Recomendado
Clasificación