Inicialização EF extremamente lenta - 15 minutos
Há algum tempo, criei um sistema no qual o usuário pode definir categorias com arquivos personalizados para alguns objetos. Então, cada objeto tem FieldValue com base em sua categoria. Classes abaixo:
public class DbCategory
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public TextDbField MainField { get; set; }
public List<DbField> Fields { get; set; }
}
public class DbObject
{
public int Id { get; set; }
public byte[] Bytes { get; set; }
[Required]
public DbCategory Category { get; set; }
public TextDbFieldValue MainFieldValue { get; set; }
public List<DbFieldValue> FieldsValues { get; set; }
}
public abstract class DbField
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public bool Required { get; set; }
}
public class IntegerDbField : DbField
{
public int? Minimum { get; set; }
public int? Maximum { get; set; }
}
public class FloatDbField : DbField
{
public double? Minimum { get; set; }
public double? Maximum { get; set; }
}
//... few other types
public abstract class DbFieldValue
{
[Key]
public int Id { get; set; }
[Required]
public DbField Field { get; set; }
[JsonIgnore]
public abstract string Value { get; set; }
}
public class IntDbFieldValue : DbFieldValue
{
public int? IntValue { get; set; }
public override string Value
{
get { return IntValue?.ToString(); }
set
{
if (value == null) IntValue = null;
else IntValue = int.Parse(value);
}
}
}// and other FieldValue types
Na minha máquina de desenvolvimento (i5, 16bg ram e unidade ssd), o banco de dados (no SqlExpress) com 4 categorias, cada um com 5-6 campos, 10k registros, a primeira consulta leva cerca de 15s. Essa primeira consulta é
var result = db.Objects
.Include(s => s.Category)
.Include(s => s.Category.MainField)
.Include(s => s.MainFieldValue.Field)
.Include(s => s.FieldsValues.Select(f => f.Field))
.Where(predicate ?? AlwaysTrue)
.ToArray();
Eu faço isso para carregar tudo na memória. Então, trabalho na lista em cache e apenas escrevo as alterações no banco de dados. Eu faço isso, porque o usuário pode executar a pesquisa com filtro em cada FieldValue. A consulta ao banco de dados sempre foi muito lenta - essa parte, no entanto, funciona muito bem.
Problema ocorre mais tarde. Alguns clientes definiram 6 categorias com mais de 20 campos em cada um e armazenam mais de 70k registros; a inicialização leva mais de 15 minutos às vezes. Depois disso, não há diferença na velocidade entre 5k e 50k.
Todas as técnicas para melhorar o código EF A primeira vez que iniciei o processo considera principalmente o cache de criação de exibição, aumentando o EF e assim por diante, mas nesse caso o tempo de inicialização aumenta após a adição de mais registros, não mais tipos de entidades.
Sei que isso é causado pela complexidade do esquema, mas há alguma maneira de acelerar isso? Felizmente, este é o Windows Service, portanto, uma vez iniciado, ele dura semanas, mas ainda assim.
Devo largar o EF para a primeira carga e fazê-lo em SQL puro? Devo fazer isso em lotes? Devo mudar EF para nHibernate? Ou alguma outra coisa? Em servidores virtualizados durante a execução desta linha, este programa maximiza a CPU (não o servidor SQL, mas o meu aplicativo).
Tentei carregar apenas objetos e depois carregar suas propriedades mais tarde. Isso foi um pouco mais rápido (mas não notavelmente) em bancos de dados pequenos, mas é ainda mais lento em bancos de dados maiores. Qualquer ajuda é apreciada, mesmo que a resposta seja "aguarde e aguarde".