Identificando el Problema de Rendimiento
Recientemente, un usuario reportó que la carga de la lista de hogares tomaba entre 3 y 4 segundos. El sgiuiente fragmento SQL fue capturado con SQL Server Profiler: ``` SELECT [p].[Id], [p].[Nombre], [p].[PropietarioId], [p].[FechaCreacion], [o].[Id], [o].[Nombre], [o].[Nivel], [o].[NivelVIP] FROM [Hogares] AS [p] LEFT JOIN [Inmortales] AS [o] ON [p].[PropietarioId] = [o].[Id] WHERE [p].[Tipo] = 1 ORDER BY [p].[FechaCreacion] DESC
Herramientas de Diagnóstico
---------------------------
### 1. Registro de Logs en EF Core
Se puede configurar el registro de logs para obtener más detalles sobre las consultas generadas por EF Core. ```
builder.Services.AddDbContext<contextocultivo>(opciones =>
opciones.UseSqlServer(cadenaConexion)
.LogTo(Console.WriteLine, LogLevel.Information));</contextocultivo>
2. Análisis del Plan de Ejecución
Ejecutando SET STATISTICS IO ON antes de la consulta se observa que hay 1245 lecturas lógicas y se está realizando un escaneo de tabla en lugar de una búsqueda por índice. ### 3. Monitoreo con Application Insights
Se utiliza TelemetryClient para medir el tiempo de ejecución de la consulta. ```
var telemetry = new TelemetryClient();
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
var hogares = await contexto.Hogares .Include(h => h.Propietario) .Where(h => h.Tipo == TipoHogar.Normal) .OrderByDescending(h => h.FechaCreacion) .ToListAsync();
stopwatch.Stop(); telemetry.TrackMetric("DuracionConsultaHogares", stopwatch.ElapsedMilliseconds);
Técnicas de Optimización
------------------------
### 1. Carga Selectiva
En lugar de cargar toda la información del propietario, solo se seleccionan los campos necesarios. ```
var hogares = await contexto.Hogares
.Select(h => new HogarDTO
{
Id = h.Id,
Nombre = h.Nombre,
NombrePropietario = h.Propietario.Nombre,
FechaCreacion = h.FechaCreacion
})
.ToListAsync();
2. Paginación
Se implementa paginación para cargar solo una cantidad limitada de registros a la vez. ``` var tamanoPagina = 20; var numeroPagina = 1;
var hogares = await contexto.Hogares .OrderBy(h => h.FechaCreacion) .Skip((numeroPagina - 1) * tamanoPagina) .Take(tamanoPagina) .ToListAsync();
### 3. Índices Optimizados
Se configuran índices compuestos para mejorar el rendimiento de las consultas. ```
constructorModelo.Entity<hogar>()
.HasIndex(h => new { h.Tipo, h.FechaCreacion })
.IncludeProperties(h => new { h.Nombre, h.PropietarioId });</hogar>
4. Consultas Sin Rastreo
Para consultas de solo lectura, se utiliza AsNoTracking para evitar el seguimiento de cambios. ```
var hogar = await contexto.Hogares
.AsNoTracking()
.FirstAsync(h => h.Id == id);
### 5. Operaciones en Lote
Se realiza una inserción en lote en lugar de insertar cada elemento individualmente. ```
contexto.AddRange(elementos);
await contexto.SaveChangesAsync();
6. Consultas Compiladas
Se utilizan consultas compiladas para evitar la recompilación constante de las mismas consultas. ``` private static readonly Func> ObtenerHogarPorId = EF.CompileAsyncQuery((ContextoCultivo db, int id) => db.Hogares.FirstOrDefault(h => h.Id == id));
var hogar = await ObtenerHogarPorId(contexto, id);
Nuevas Características en EF Core 8
-----------------------------------
### 1. Actualizaciones y Eliminaciones en Lote
Se pueden realizar actualizaciones y eliminaciones directamente en la base de datos sin cargar los objetos en memoria. ```
await contexto.Hogares
.Where(h => h.Nivel < 5)
.ExecuteUpdateAsync(establecer => establecer.SetProperty(h => h.Nivel, 5));
2. Consultas en Columnas JSON
Se pueden consultar atributos dentro de columnas JSON. ``` var hogares = await contexto.Hogares .Where(h => h.MetadataJson.Contains(""VIP": true")) .ToListAsync();
Comparación de Rendimiento
--------------------------
| Métrica | Antes de la Optimización | Después de la Optimización | Aumento del Rendimiento |
|---|---|---|---|
| Carga de Lista de Hogares | 3200 ms | 450 ms | 7 veces |
| Inserción de 1000 Registros | 30 s | 1.2 s | 25 veces |
| Ocupación Máxima de CPU | 85% | 25% | Disminución significativa |
| Consumo de Memoria | 420 MB | 180 MB | 57% menos |