Estoy escribiendo un código que atraviesa grandes cantidades de datos de imágenes, preparando un gran bloque delta que lo contiene todo comprimido para enviar.
Aquí hay una muestra de cómo podrían ser estos datos
[MessagePackObject]
public class Blob : VersionEntity
{
[Key(2)]
public Guid Id { get; set; }
[Key(3)]
public DateTime CreatedAt { get; set; }
[Key(4)]
public string Mediatype { get; set; }
[Key(5)]
public string Filename { get; set; }
[Key(6)]
public string Comment { get; set; }
[Key(7)]
public byte[] Data { get; set; }
[Key(8)]
public bool IsTemporarySmall { get; set; }
}
public class BlobDbContext : DbContext
{
public DbSet<Blob> Blob { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blob>().HasKey(o => o.Id);
}
}
Cuando trabajo con esto, proceso todo en un flujo de archivos, y quiero mantener la menor cantidad posible en la memoria en cualquier momento.
¿Es suficiente hacerlo así?
foreach(var b in context.Where(o => somefilters).AsNoTracking())
MessagePackSerializer.Serialize(stream, b);
¿Esto todavía llenará la memoria con todos los registros de blob, o serán procesados uno por uno a medida que itere en el enumerador? No está utilizando ninguna lista de ToList, solo el enumerador, por lo que Entity Framework debería poder procesarlo sobre la marcha, pero no estoy seguro de si eso es lo que hace.
Cualquier experto en Entity Framework aquí que pueda dar alguna orientación sobre cómo se maneja esto correctamente.
stream
viene?). Finalmente, el manejo rápido de datos y transmisión de archivos de SQL Server requiere un enfoque diferente que va más allá de EF.Respuestas:
En general, cuando crea un filtro LINQ en una entidad, es como escribir una declaración SQL en forma de código. Devuelve un archivo
IQueryable
que no se ha ejecutado realmente en la base de datos. Cuando itera sobreIQueryable
con unaforeach
llamada oToList()
se ejecuta el sql y todos los resultados se devuelven y se almacenan en la memoria.https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution
Si bien EF no es la mejor opción para un rendimiento puro, hay una forma relativamente simple de manejar esto sin preocuparse demasiado por el uso de la memoria:
Considera lo siguiente
Ahora ha filtrado los blobs de acuerdo con sus requisitos, y ejecutó esto en la base de datos, pero solo devolvió los valores de Id en la memoria.
Entonces
El blob grande debe estar disponible para la recolección de basura una vez que haya terminado con él, y no debe quedarse sin memoria.
Obviamente, puede verificar el número de registros en la lista de identificación, o puede agregar metadatos a la primera consulta para ayudarlo a decidir cómo procesarlo si desea refinar la idea.
fuente
Id
tiene un índice agrupado, el rendimiento de muchas consultas secuenciales puede no ser tan malo como cree.