entityframework[1]

Entity Framework – Melhorando performance para consulta ReadOnly 6


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.

Elapsed Title
00:00:01.4098212 ADO Puro
00:00:01.4771617 Dapper
00:00:06.1009449 Entity Framework
00:00:01.6514433 Entity Framework Fast
00:00:06.5666193 NHibernate

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


sobre Alberto Monteiro

Desenvolvedor no Grupo Fortes, cuja principal área de conhecimento são em tecnologias Microsoft, como Windows Forms / Services, WPF, ASP.NET(MVC/WEB API), Windows Phone, EF. Gosta de sopa de letrinhas(SOLID, DDD, TDD, BDD, IoC, SoC, UoW), possui aplicações de Windows Phone publicadas no marketplace, já contribuiu no jQuery UI. Atualmente trabalha com ASP.NET MVC / Web API, Windows Azure, Amazon AWS, jQuery/UI, Knockout, EF, Ninject, AutoMapper, Restfulie, SignalR, KendoUI.

  • Fernando Silva

    Excelente artigo Alberto,
    meus parabéns, seu mais um item que pode aumentar a performance para
    consultas, http://goo.gl/sI2tgX.

  • Ótima contribuição Fernando, editei o artigo e coloquei o link que você passou e mais outros!!!
    Obrigado pelo seu comentário!

  • Fúlvio

    Parabéns Alberto Monteiro, é isso ai mesmo, quando se sabe usar, sabe tirar o maior proveito do Entity …

    Muito bom o que fez!

  • Kevin Allen

    Poderia ter uma explicação sobre o que cada coisa que você desativou faz, para que quem leia possa entender.

    Valeu pela dica!

  • Kevin Allen eu coloquei na conclusão 2 links que aprofundam mais os detalhes de performance.
    – Performance Considerations => https://msdn.microsoft.com/en-us/library/vstudio/cc853327.aspx
    – Performance Considerations for Entity Framework 4, 5, and 6 => https://msdn.microsoft.com/en-us/data/hh949853

    A minha intenção nesse post foi mostrar que é possível ter uma melhor performance com EF, e despertar nas pessoas o senso critico para que tenham opinião própria, pois vejo alguns influenciadores da comunidade não mostram as coisas como se fossem a bala de prata, e por serem influentes as pessoas acabam seguindo cegamente, e como bala de prata não existe, na minha opinião, é sempre importante validar o que você aprende com outra pessoa e ter sua opinião própria. Por isso que eu não fui atrás de explicar o que cada linha daquela faz, só quis mostrar que é possível!!

  • Sou fã do seu trabalho, Alberto. Realmente restringiu bem a necessidade de trabalhar com múltiplos ORMs – salvo em casos realmente atípico. Fantástico!