Veja como melhorar a performance do Entity Framework

Veja como melhorar a performance do Entity Framework

Boas práticas para melhorar a performance do EF

Hoje venho compartilhar através deste artigo, boas práticas que tenho aplicado em meu projetos com Entity Framework com a finalidade de melhorar sua performance.

Irei dar algumas dicas que poderão ser utilizados para quem utiliza outro tipo de ORM sem ser o Entity Framework.

São dicas simples que farão toda a diferença na performance de sua aplicação. Vamos as dicas!

Não deixe a instância de seus DbContexts abertas muito tempo.
DbContext é responsável por manipular os registros do banco de dados gerenciando todo o ciclo de vida dessas informações em memória. Com isso ele utiliza vários recursos como cache de entidades, controles de instâncias, controle de alterações, versionamentos de alterações em memória e etc. Pelo que podemos ver o DbContext é responsável por gerenciar uma série de recursos e informações, se você fizer mal uso dele, vai acabar consumindo muito mais recursos do que o necessário, ou seja, você poderá ter muitos dados em memória sem utilização aguardando o Garbage Collector passar para liberar este espaço.

Para garantirmos uma boa utilização do DbContext, aconselho sempre utilizar o mesmo dentro de um bloco Using, assim ao final do bloco o Dispose() será executado automáticamente, evitando de esquecer de tira-lo da memória.

ex:

Utilize o Change Tracking somente quanto for necessário
Sabemos que o DbContext controla o estado de cada entidade que está sendo manipulada, assim ele sabe se algum registro foi alterado, excluído ou até mesmo inserido. Só que muita das vezes nós pegamos algumas informações que iremos somente utilizar no modo consulta, ou seja, não temos intenção de alterar aquela informação. Neste cenário bem específico que só queremos pegar os dados e exibir em um DataGrid, GridView, Combobox ou até mesmo um relatório, não precisamos deixar ativo o recurso Change Tracking. Para desabilitar este recurso é bem simples, basta fazermos o uso do método “AsNoTracking()” em suas consultas, assim ele não irá mapear qualquer tipo de alteração realizada em cada registro. Veja um exemplo do uso do método:

 

Queries muito complexas
Sabemos que o Entity Framework converte as queries de LINQ para código SQL, e isso funciona muito bem. Mas em casos de queries muito complexas, que acabam trabalhando com recursividade, ou que acaba utilizando comando analíticos, o uso do LINQ não é muito aconselhável.
Neste cenário eu costumo utilizar views ou procedures, com isso eu acabo tendo vários tipos de benefícios que o próprio banco de dados me oferece, como por exemplo realizar cache do algorítimo de minhas consultas SQL, criação do plano de execução e etc.

Cuidado para não executar a queries antes da hora através dos operadores
Ao montarmos nossa query é muito comum utilizarmos alguns comandos como Count(), ToList(), ToArray(), ToSequence(), First(), FirstOrDefault(), Last() e LastOrDefault(). O que muitos não sabem é que estes métodos forçam a execução das queries no banco de dados.
Se fizer mal uso desses operadores, você poderá mandar executar sua querie mais de uma vez no banco de dados sem necessidade.

Veja o exemplo abaixo. Ele apresenta uma query bastante simples que faz um JOIN entre duas entidades de um mesmo contexto. Esse cenário é bastante simples e comum de ser encontrado em qualquer sistema. Mas se notarmos o uso dos operadores ToList() veremos que eles são utilizados dentro da query. O mau posicionamento destes operadores dentro da query afeta diretamente o modo como ela será executada.

Ao invés do join entre as entidades ser executado no banco de dados ele será executado em memória, exigindo que todos os registros de “Pilots” e “FlightCompanies” sejam carregados em memória (mesmo que não exista nenhuma relação entre eles), para que então, os dados sejam relacionados.
Erroneamente pode-se imaginar que isso não faz diferença alguma, mas isso faz toda a diferença entre um sistema rápido e performático, ao invés de um sistema lento e que consome muito mais memória do que o necessário.
O modo correto de executar a query é o modo apresentado abaixo:

 

Utilize o AsEnumerable() somente quando for necessário
Cuidado ao usar o operador AsEnumerable() sem que ele realmente seja necessário.
Veja o erro apresentado abaixo:

O uso do método AsEnumerable() realmente não faz sentido nessa query, pois o retorno da query já implementa a interface IQueryable, que por sua vez implementa a interface IEnumerable, que é complementada pelo extension method Enumerable.ToList. Ele pode realmente ser removido da query e irá melhorar a performance, pois será um método a menos a ser executado sobre todo o conjunto retornado pelo banco de dados.

Evite retornar mais registros do que o necessário
Outro erro é forçar o banco de dados retornar mais registros do que o necessário. A query abaixo demonstra este cenário no qual todo um conjunto de registros é retornado, mas apenas um registro é utilizado.

 

Note que a query é construída, todos os registros são retornados, mas apenas o primeiro é utilizado, pois após a execução do operador ToList() invocamos o operador First(). Esse cenário é bastante ruim, pois mais registros do que o necessário foram trafegados entre o banco de dados e a aplicação, estes registros foram mapeados pelo Entity Framework (mais consumo de memória e processamento) e após isso utilizamos apenas o primeiro deles (comportamento resultante da execução do operador First()).

Evite de filtrar o registro somente em memória
No cenário abaixo é feita uma requisição ao banco de dados que por sua vez devolve os dados para o Entity Framework que acaba colocando tudo em memória e só depois é realizado o filtro. Este é um cenário que precisamos evitar, pois devemos já fazer a requisição para o banco de dados com o filtro já determinado. Veja abaixo o exemplo do mau uso e do indicado:

 

Cuidado com Lazy Loading
O Lazy Loading é um excelente recurso quando utilizado da forma correta. Para muitos ele funciona de forma atraente, pois carrega os dados agregados apenas quando precisamos deles (por isso o nome “lazy loading”). Mas esse comportamento pode consumir mais recursos do que o necessário em cenários específicos. Veja o exemplo abaixo:

 

Note que está sendo passado como parâmetro para o método “SendPayment” o valor de uma propriedade de uma associação da classe Employe. Utilizando Lazy Loading neste exemplo acabaremos por ter um grande número de requisições ao banco de dados, sendo: uma requisição para selecionar as instâncias de Employee; e N requisições (dado o número de registros retornados pela primeira query) para consulta dos dados de BanckAccount. Assim, o resultado final de chamadas ao banco de dados será de N + 1 (dado que N é o número de registros de Employe).
Para reverter este cenário basta fazer uso do operador Include, indicando qual propriedade agregada deve ser retornada na query. A resolução pode ser vista abaixo:

 

Dessa maneira apenas uma requisição será feita ao banco de dados, retornando os dados de Employe e os dados de BanckAccount.

Simplifique o retorno de suas consultas apenas com os dados que precisa
Traga somente as informações que irão de fatos ser usadas posteriormente.
Dado o exemplo abaixo, é fácil notar que para execução da operação apenas os campos Id e BankAccount.Number de cada Employe são suficientes. Mas, apesar disso, notamos que todos os campos de Employe e BackAccount são retornados.

 

Utilizando recursos semelhantes ao NOLOCK
O comando NOLOCK não é suportado pelo Entity Framework, isto é, não existe um meio de “ligar ou desligar” o seu uso. Mas podemos alterar o nível de isolamento das transações, o que “no fim das contas”, gera os mesmos resultados. No exemplo abaixo é apresentada essa prática, onde o nível de isolamento da transação é alterado.

 

Utilize Cache
Podemos utilizar Cache em consultas que irão sofrer poucas alterações, como algumas tabelas de domínio. Com isso iremos melhorar e muito a performance do nosso querido Entity Framework.

Espero que este artigo possa lhe ajudar a melhorar bastante a performance de sua aplicação.

 

Fonte: ferhenriquef.com

Previous Curso completo de Node.Js em português
Next Curso grátis e completo sobre Scrum

About author

Paulo Rogério
Paulo Rogério 141 posts

Sou apaixonado por tecnologia e adoro criar aplicações desktop, web e mobile. Adoro aprender e compartilhar conhecimento, meu hobby é ajudar as pessoas.

You might also like

Banco de dados 0 Comments

Conheça Algumas rotinas que facilitam nosso desenvolvimento no MySql

Share this on WhatsAppConfira algumas consultas Sql que podem agilizar seu dia a dia no MySql Hoje venho trazer algumas rotinas uteis que costumo utilizar em meu dia a dia na

Banco de dados 0 Comments

Aula – Utilizando code-first e migrations no EntityFramework

Share this on WhatsAppGerencie seu banco de dados através do Entity Framework Hoje resolvi fazer um vídeo para ajudar a galera que ainda não entendeu como podemos gerenciar nosso banco

Visual Studio 1Comments

Como gerenciar bancos de dados Sql Server no Visual Studio 2017

Share this on WhatsAppE ai pessoal, tudo certo com vocês? Bom espero que sim! Semana passada eu trouxe uma vídeo aula bem interessante de como trabalhar com MongoDb no C#,

8 Comments

  1. Sid
    abril 29, 07:36 Reply
    Olá amigo! Algumas coisas ai que eu não concordo. "Para garantirmos uma boa utilização do DbContext, aconselho sempre utilizar o mesmo dentro de um bloco Using, assim ao final do bloco o Dispose() será executado automaticamente, evitando de esquecer de tira-lo da memória." Isso não é necessariamente verdade, assim como o já foi confirmado pelo próprio time do EF http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html#.U9efX_ldXpo. O método Dispose() só deve ser obrigatoriamente chamado caso você tenha aberto a conexão manualmente. Mas uma coisa é verdade, o usuário teria que esperar o GC limpar o objeto. Entretanto, o "dispose()" é automaticamente chamado ao fim de cada operação. Sendo assim, não utilizar o "using" não significa que o objeto não foi "disposed". Outro fato é que ao usar o "using", o usuário estaria perdendo boa partes dos recursos do EF, que é o First Level Cache, Mapa das Entidades, Change Tracking e Lazy-Loading Abilities. De resto eu gostei bastante! Parabéns!
  2. Henrique Lobo
    abril 29, 12:49 Reply
    Oi, acabei de descobrir o seu blog e gostei bastante. Estou retomando meus estudos em .net para um projeto e encontrei material bem interessante aqui, parabéns! Aproveito para te convidar a participar de um projeto que mantenho, chamado /dev/All - é um agregador de blogs voltado para a comunidade de desenvolvedores. Cadastrando o RSS do seu blog no site (link "Cadastre seu blog"), você fornece o RSS e as pessoas saberão quando um post novo apareceu aqui no seu site. Seria bem legal ver seus posts na nossa página inicial, mais uma vez, parabéns pelo conteúdo!
    • paulorogerio
      abril 29, 20:02 Reply
      Depois me chama no Face e me apresenta seu projeto. A ideia aqui é só ajudar as pessoas
  3. Lailson
    abril 29, 14:21 Reply
    Muito legal cara, parabéns pelo post.
  4. Leonardo Lima
    maio 06, 15:30 Reply
    Muito Bom Paulo. Algumas pessoas ainda torcem o nariz para o uso do Entity Framework. Mas sabendo utiliza-lo e quando o banco de dados é SQL, facilita mais ainda. Parabéns !!!
  5. Guih
    junho 17, 02:24 Reply
    Alguma dica para a primeira query ? Na primeira query é realizado toda montagem dos arquivos do entity , sendo assim a query mais lenta do sistema, Meu site de e-commerce demora mto pra trazer 4 registros apenas
    • paulorogerio
      junho 18, 20:16 Reply
      Tem que analisar sua query, talvez você esteja filtrando por um campo de sua tabela que não tenha índice.
  6. GabrielScavassa
    julho 12, 13:31 Reply
    Paulo, muito boa as dias. Só não entendi o seguinte: No tópico Utilizando recursos semelhantes ao NOLOCK ao final você faz tran.Commit(), como é uma consulta, qual o motivo de utilizar o commit? Sempre que utilizar transaction deve-se usar o commit ?

Leave a Reply