Eu segui o mantra "Não otimize prematuramente" e codifiquei meu serviço WCF usando o Entity Framework.
No entanto, fiz o perfil do desempenho e o Entity Framework é muito lento. (Meu aplicativo processa 2 mensagens em cerca de 1,2 segundos, em que o aplicativo (legado) que estou reescrevendo faz de 5 a 6 mensagens ao mesmo tempo. (O aplicativo legado chama sprocs para seu acesso ao banco de dados.)
Minha criação de perfil aponta para o Entity Framework levando a maior parte do tempo por mensagem.
Então, quais são minhas opções?
Existem ORMs melhores por aí?
(Algo que apenas suporta a leitura normal e escrita de objetos e faz isso rápido ..)Existe uma maneira de tornar o Entity Framework mais rápido?
( Observação : quando digo mais rápido, quero dizer a longo prazo, não a primeira chamada. (A primeira chamada é lenta (15 segundos para uma mensagem), mas isso não é um problema. Eu só preciso que seja rápido para o resto das mensagens.)Alguma terceira opção misteriosa que me ajudará a obter mais velocidade do meu serviço.
NOTA: A maioria das minhas interações com o banco de dados são criar e atualizar. Eu faço muito pouco selecionando e excluindo.
fonte
Respostas:
Você deve começar criando o perfil dos comandos SQL realmente emitidos pelo Entity Framework. Dependendo da sua configuração (POCO, entidades de auto-rastreamento), há muito espaço para otimizações. Você pode depurar os comandos SQL (que não devem diferir entre o modo de depuração e o modo de liberação) usando o
ObjectSet<T>.ToTraceString()
método. Se você encontrar uma consulta que requer otimização adicional, você pode usar algumas projeções para fornecer à EF mais informações sobre o que você está tentando realizar.Exemplo:
Pode ser substituído por:
Acabei de digitar isso da minha cabeça, então não é exatamente assim que seria executado, mas EF na verdade faz algumas ótimas otimizações se você disser tudo o que sabe sobre a consulta (neste caso, que precisaremos da categoria- nomes). Mas isso não é como o carregamento antecipado (db.Products.Include ("Categories")) porque as projeções podem reduzir ainda mais a quantidade de dados a serem carregados.
fonte
O fato é que produtos como o Entity Framework SEMPRE serão lentos e ineficientes, pois estão executando muito mais código.
Também acho bobagem que as pessoas estejam sugerindo que se deve otimizar consultas LINQ, olhar para o SQL gerado, usar depuradores, pré-compilar, realizar muitas etapas extras, etc., ou seja, perder muito tempo. Ninguém diz - simplifique! Todo mundo quer complicar ainda mais as coisas dando ainda mais passos (perda de tempo).
Uma abordagem de bom senso seria não usar EF ou LINQ. Use SQL simples. Não há nada de errado com isso. Só porque existe uma mentalidade de rebanho entre os programadores e eles sentem o desejo de usar cada um dos novos produtos que existem, não significa que seja bom ou funcione. A maioria dos programadores pensa que se incorporar cada novo trecho de código lançado por uma grande empresa, isso os tornará um programador mais inteligente; não é verdade. A programação inteligente é principalmente sobre como fazer mais com menos dores de cabeça, incertezas e no mínimo de tempo. Tempo de lembrar! Esse é o elemento mais importante, então tente encontrar maneiras de não desperdiçá-lo na resolução de problemas em código ruim / inchado escrito simplesmente para se conformar com alguns chamados 'padrões' estranhos
Relaxe, aproveite a vida, faça uma pausa na codificação e pare de usar recursos extras, código, produtos, 'padrões'. A vida é curta e a vida do seu código é ainda mais curta, e certamente não é ciência de foguetes. Remova camadas como LINQ, EF e outras e seu código será executado com eficiência, escalonará e, sim, ainda será fácil de manter. Abstração demais é um 'padrão' ruim.
E essa é a solução para o seu problema.
fonte
Uma sugestão é usar LINQ to Entity Framework apenas para instruções CRUD de registro único.
Para consultas, pesquisas, relatórios, etc. mais envolvidos, escreva um procedimento armazenado e adicione-o ao modelo Entity Framework conforme descrito no MSDN .
Esta é a abordagem que usei com alguns dos meus sites e parece ser um bom meio-termo entre produtividade e desempenho. O Entity Framework nem sempre gerará o SQL mais eficiente para a tarefa em questão. E, em vez de perder tempo tentando descobrir o porquê, escrever um procedimento armazenado para as consultas mais complexas realmente economiza tempo para mim. Depois de familiarizar-se com o processo, não é muito complicado adicionar procs armazenados ao seu modelo EF. E, claro, o benefício de adicioná-lo ao seu modelo é que você obtém todas as vantagens fortemente tipadas que vêm de usar um ORM.
fonte
Se você é puramente buscando dados, é uma grande ajuda para o desempenho quando você diz ao EF para não manter o controle das entidades que ele busca. Faça isso usando MergeOption.NoTracking. EF irá apenas gerar a consulta, executá-la e desserializar os resultados para os objetos, mas não tentará rastrear as mudanças de entidade ou qualquer coisa dessa natureza. Se uma consulta for simples (não gasta muito tempo esperando o retorno do banco de dados), descobri que configurá-la como NoTracking pode dobrar o desempenho da consulta.
Consulte este artigo do MSDN no enum MergeOption:
Resolução de identidade, gerenciamento de estado e controle de mudanças
Este parece ser um bom artigo sobre o desempenho da EF:
Desempenho e Estrutura da Entidade
fonte
Você diz que traçou o perfil do aplicativo. Você também traçou o perfil do ORM? Existe um profiler EF de Ayende que irá destacar onde você pode otimizar seu código EF. Você pode encontrá-lo aqui:
http://efprof.com/
Lembre-se de que você pode usar uma abordagem SQL tradicional junto com seu ORM se precisar para obter desempenho.
Se houver um ORM mais rápido / melhor? Dependendo do seu modelo de objeto / dados, você pode considerar o uso de um dos micro-ORMs, como Dapper , Massive ou PetaPoco .
O site do Dapper publica alguns benchmarks comparativos que darão uma ideia de como eles se comparam a outros ORMs. Mas é importante notar que os micro-ORMs não suportam o rico conjunto de recursos dos ORMs completos, como EF e NH.
Você pode querer dar uma olhada em RavenDB . Este é um banco de dados não relacional (de Ayende novamente) que permite armazenar POCOs diretamente sem a necessidade de mapeamento . RavenDB é otimizado para leituras e torna a vida do desenvolvedor muito mais fácil, removendo a necessidade de manipular o esquema e mapear seus objetos para esse esquema. No entanto, esteja ciente de que esta é uma abordagem significativamente diferente do uso de uma abordagem ORM e estes são descritos no site do produto .
fonte
Achei a resposta de @Slauma aqui muito útil para acelerar as coisas. Usei o mesmo tipo de padrão para inserções e atualizações - e o desempenho disparou.
fonte
Pela minha experiência, o problema não é com a EF, mas com o próprio ORM.
Em geral, todos os ORMs sofrem de problemas N + 1, consultas não otimizadas e etc. Meu melhor palpite seria rastrear as consultas que causam degradação de desempenho e tentar ajustar a ferramenta ORM ou reescrever essas partes com SPROC.
fonte
Esta é uma opção simples, sem estrutura e sem ORM, que carrega a 10.000 / segundo com 30 campos ou mais. Executando em um laptop antigo, provavelmente mais rápido do que em um ambiente real.
https://sourceforge.net/projects/dopersistence/?source=directory
fonte
Eu encontrei esse problema também. Eu odeio abandonar o EF porque funciona tão bem, mas é lento. Na maioria dos casos, desejo apenas encontrar um registro ou atualizar / inserir. Mesmo operações simples como essa são lentas. Retirei 1100 registros de uma tabela em uma lista e essa operação levou 6 segundos com EF. Para mim, isso é muito longo, mesmo para salvar demora muito.
Acabei fazendo meu próprio ORM. Eu puxei os mesmos 1100 registros de um banco de dados e meu ORM levou 2 segundos, muito mais rápido do que EF. Tudo com meu ORM é quase instantâneo. A única limitação agora é que ele só funciona com o MS SQL Server, mas pode ser alterado para funcionar com outros como o Oracle. Eu uso o MS SQL Server para tudo agora.
Se você gostaria de experimentar meu ORM, aqui está o link e o site:
https://github.com/jdemeuse1204/OR-M-Data-Entities
Ou se você quiser usar o nugget:
PM> Instalar-Pacote OR-M_DataEntities
A documentação também está lá
fonte
Só faz sentido otimizar depois de definir o perfil. Se você descobrir que o acesso ao banco de dados é lento, você pode converter para o uso de procedimentos armazenados e manter o EF. Se você descobrir que é o próprio EF que está lento, pode ser necessário alternar para um ORM diferente ou não usar um ORM.
fonte
Temos um aplicativo semelhante (Wcf -> EF -> banco de dados) que faz 120 solicitações por segundo facilmente, então estou mais do que certo de que EF não é o seu problema aqui. Dito isso, tenho visto grandes melhorias de desempenho com consultas compiladas.
fonte
Usei EF, LINQ to SQL e dapper. Dapper é o mais rápido. Exemplo: eu precisava de 1000 registros principais com 4 sub-registros cada. Usei o LINQ to sql, demorou cerca de 6 segundos. Em seguida, mudei para dapper, recuperei 2 conjuntos de registros do único procedimento armazenado e, para cada registro, adicionei os sub-registros. Tempo total 1 segundo.
Além disso, o procedimento armazenado usou funções de valor de tabela com aplicação cruzada, descobri que as funções de valor escalar são muito lentas.
Meu conselho seria usar EF ou LINQ to SQL e, em certas situações, mudar para dapper.
fonte
O Entity Framework não deve causar grandes gargalos. Provavelmente, existem outras causas. Você pode tentar mudar o EF para o Linq2SQL, ambos têm recursos de comparação e o código deve ser fácil de converter, mas em muitos casos o Linq2SQL é mais rápido do que o EF.
fonte