Estou escrevendo um código que percorre grandes quantidades de dados de imagem, preparando um grande bloco delta contendo tudo compactado para envio.
Aqui está uma amostra de como esses dados podem ser
[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);
}
}
Ao trabalhar com isso, processo tudo em um fluxo de arquivos e quero manter o mínimo possível na memória a qualquer momento.
É o suficiente para fazer assim?
foreach(var b in context.Where(o => somefilters).AsNoTracking())
MessagePackSerializer.Serialize(stream, b);
Isso ainda preencherá a memória com todos os registros de blob ou eles serão processados um por um, conforme eu iterar no enumerador. Ele não está usando nenhum ToList, apenas o enumerador; portanto, o Entity Framework deve poder processá-lo em qualquer lugar, mas não tenho certeza se é isso que ele faz.
Qualquer especialista em Entity Framework aqui que possa dar alguma orientação sobre como isso é tratado adequadamente.
stream
vem?). Por fim, o manuseio rápido dos dados do fluxo de arquivos do SQL Server e o streaming requerem uma abordagem diferente que está além do EF.Respostas:
Em geral, quando você cria um filtro LINQ em uma Entidade, é como escrever uma instrução SQL em formato de código. Ele retorna um
IQueryable
que não foi realmente executado no banco de dados. Quando você repete a chamadaIQueryable
com aforeach
ouToList()
, o sql é executado e todos os resultados são retornados e armazenados na memória.https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution
Embora a EF talvez não seja a melhor opção para desempenho puro, existe uma maneira relativamente simples de lidar com isso sem se preocupar muito com o uso de memória:
Considere o seguinte
Agora você filtrou os Blobs de acordo com seus requisitos e executou isso no banco de dados, mas retornou apenas os valores de ID na memória.
Então
O blob grande deve estar disponível para coleta de lixo assim que você terminar e não ficará sem memória.
Obviamente, você pode verificar o número de registros na lista de IDs ou adicionar metadados à primeira consulta para ajudá-lo a decidir como processá-lo, se quiser refinar a ideia.
fonte
Id
índice tenha um cluster, o impacto no desempenho de muitas consultas seqüenciais pode não ser tão ruim quanto você pensa.