Entity Framework — Melhorando performance para consulta ReadOnly

Fala galera, beleza?

A preocupação com a performance é algo essencial para o desenvolvedor, e esse artigo está focado em melhorar as consultas geradas pelo Entity Framework quando temos um cenário ReadOnly, ou seja, um cenário onde os dados vão ser apensar consultados, e não será preciso alterá-los.

Motivação

Após ver um vídeo de comparação entre algumas opções de acesso a dados, vi que o Entity Framework teve um resultado bem fraco comparado aos melhores, nessa comparação, foram usados 4 alternativas, são elas:

  • ADO.NET Puro
  • Dapper
  • Entity Framework 6+
  • NHibernate 4+

Então decidi fazer esse artigo, e você também pode ver o vídeo(que está lá em baixo) que demonstro a execução da implementação que fiz para melhorar a performance do EF.

Entity Framework Tunning

Após visualizar os resultados da medição que foi realizada, na qual ADO.NET puro e Dapper tiveram um resultado bem melhor. Sendo assim para repositórios somente leitura, é defendido o uso do Dapper, particularmente, gosto de manter a menor quantidade de dependências possíveis no projeto, e nesse caso a principio, IMHO não vejo por quer usar outra alternativa, já que o ganho das melhores opções não foram algo do outro mundo.
Fiz um fork do projeto DataAccessTest do André Baltieri e fiz algumas alterações.

A primeira coisa que eu fiz, foi trocar a forma de mensurar o tempo, no código original está sendo usada DateTime.Now, porém existe uma classe que poucos conhecem quem tem justamente essa finalidade, é a classe Stopwatch, então, sempre que for medir tempo, use ela, essa é a sua responsabilidade, muito mais eficaz que usar DateTime.

Para uma exibição mais agradável, alterei para um formato tabular.

Logo em seguida, fui de fato implementar a consulta com EF que seria mais performatica, basicamente eu fiz 2 coisas, uma foi configurar o EF da seguinte maneira:

var db = new DataContext();
db.Configuration.AutoDetectChangesEnabled = false;
db.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
db.Configuration.LazyLoadingEnabled = false;
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.UseDatabaseNullSemantics = false;
db.Configuration.ValidateOnSaveEnabled = false;

E a outra foi usar o método AsNoTracking que também desliga algumas coisas do Entity Framework.

Resultados

Após esses pequenos ajustes e a nova implementação, é a hora de ver os resultados, então apertei CTRL + F5 e aguardei a tabela com os resultados.

A implementação que eu fiz, incluiu a linha do Entity Framework Fast. Veja que a diferença entre os dois melhores resultado e o resultado o EF Fast foram bem próximos.
Você pode acessar todo o código fonte do código no meu fork do github clicando aqui.

Vídeo

Conclusão

Como disse anteriormente, gosto de manter a menor quantidade possível de dependências, e com esses resultados, para a grande maioria dos cenários, não troco o EF por nenhum outro, e se for um cenário mais crítico, usaria ADO.NET puro, é claro que tem varias outras formas, mas resumidamente é isso.

Espero que vocês tenham gostado, fique a vontade para comentar!!

Era isso galera, até a próxima.

[Atualização]

Segue uma ótima contribuição do Fernando Silva que indicou o artigo: Colocando o mapeamento das views em Cache no Entity Framework
Vale a pena também dar uma olhada nesses links:
- CLR Method to Canonical Function Mapping
- Performance Considerations
- Performance Considerations for Entity Framework 4, 5, and 6