Pergunta

Eu tenho um aplicativo que usa NHibernate como ORM e às vezes apresenta problemas de desempenho devido à forma como os dados estão sendo acessados ​​por ele.Que tipo de coisas podem ser feitas para melhorar o desempenho do NHibernate?(Limite a uma recomendação por resposta)

Foi útil?

Solução

O primeiro e mais dramático problema de desempenho que você pode encontrar com o NHibernate é se você estiver criando uma nova fábrica de sessões para cada sessão criada.Apenas uma instância de fábrica de sessão deve ser criada para cada execução de aplicativo e todas as sessões devem ser criadas por essa fábrica.

Nesse sentido, você deve continuar usando a mesma sessão desde que faça sentido.Isso varia de acordo com o aplicativo, mas para a maioria dos aplicativos Web, recomenda-se uma única sessão por solicitação.Se você descartar sua sessão com frequência, não obterá os benefícios de seu cache.O uso inteligente do cache de sessão pode alterar uma rotina com um número linear (ou pior) de consultas para um número constante sem muito trabalho.

Igualmente importante é que você deseja ter certeza de que está carregando lentamente suas referências de objeto.Caso contrário, gráficos de objetos inteiros poderão ser carregados até mesmo para as consultas mais simples.Existem apenas alguns motivos para não fazer isso, mas é sempre melhor começar com carregamento lento e voltar conforme necessário.

Isso nos leva à busca ansiosa, o oposto do carregamento lento.Ao percorrer hierarquias de objetos ou percorrer coleções, pode ser fácil perder o controle de quantas consultas você está fazendo e acabar com um número exponencial de consultas.A busca antecipada pode ser feita por consulta com um FETCH JOIN.Em raras circunstâncias, como se houver um determinado par de tabelas que você sempre busca juntar, considere desativar o carregamento lento para esse relacionamento.

Como sempre, o SQL Profiler é uma ótima maneira de localizar consultas lentas ou feitas repetidamente.No meu último trabalho, tínhamos um recurso de desenvolvimento que também contava consultas por solicitação de página.Um grande número de consultas para uma rotina é o indicador mais óbvio de que sua rotina não está funcionando bem com o NHibernate.Se o número de consultas por rotina ou solicitação parecer bom, provavelmente você está no ajuste do banco de dados;certificando-se de ter memória suficiente para armazenar planos de execução e dados no cache, indexando corretamente seus dados, etc.

Um pequeno problema complicado que encontramos foi com SetParameterList().A função permite passar facilmente uma lista de parâmetros para uma consulta.O NHibernate implementou isso criando um parâmetro para cada item passado.Isso resulta em um plano de consulta diferente para cada número de parâmetros.Nossos planos de execução quase sempre eram liberados do cache.Além disso, vários parâmetros podem retardar significativamente uma consulta.Fizemos um hack customizado do NHibernate para enviar os itens como uma lista delimitada em um único parâmetro.A lista foi separada no SQL Server por uma função de valor de tabela que nosso hack inseriu automaticamente na cláusula IN da consulta.Pode haver outras minas terrestres como esta, dependendo da sua aplicação.SQL Profiler é a melhor maneira de encontrá-los.

Outras dicas

O SessionFactory do NHibernate é uma operação cara, então uma boa estratégia é criar um Singleton que garanta que haja apenas UMA instância do SessionFactory na memória:

   public class NHibernateSessionManager
    {
        private readonly ISessionFactory _sessionFactory;

        public static readonly NHibernateSessionManager Instance = new NHibernateSessionManager();

        private NHibernateSessionManager()
        {
            if (_sessionFactory == null)
            {
                System.Diagnostics.Debug.WriteLine("Factory was null - creating one");
                _sessionFactory = (new Configuration().Configure().BuildSessionFactory());
            }
        }

        public ISession GetSession()
        {
            return _sessionFactory.OpenSession();
        }

        public void Initialize()
        {
            ISession disposeMe = Instance.GetSession();
        }
    }

Então, em seu Global.Asax Application_Startup, você pode inicializá-lo:

protected void Application_Start()
{
    NHibernateSessionManager.Instance.Initialize();
}

Evitar e/ou minimizar o Selecione o problema N + 1 reconhecendo quando mudar do carregamento lento para a busca antecipada para consultas de desempenho lento.

Não é uma recomendação, mas uma ferramenta para ajudá-lo:Prof NH ( http://nhprof.com/ ) parece promissor, pode avaliar o uso da estrutura ORM.Pode ser um bom ponto de partida para o ajuste do NHibernate.

Sem quaisquer detalhes sobre os tipos de problemas de desempenho que você está vendo, só posso oferecer uma generalização:Na minha experiência, a maioria dos problemas de desempenho de consultas de banco de dados surge da falta de índices adequados.Portanto, minha sugestão para uma primeira ação seria verificar seus planos de consulta para consultas não indexadas.

O NHibernate gera SQL muito rápido imediatamente.Estou usando-o há um ano e ainda não precisei escrever SQL simples com ele.Todos os meus problemas de desempenho foram de Normalização e falta de índices.

A solução mais fácil é examinar os planos de execução de suas consultas e criar índices adequados, especialmente nas colunas de chave estrangeira.Se você estiver usando o Microsoft SQL Server, o "Database Engine Tuning Advisor" ajuda muito com isso.

Apenas "Uma recomendação por resposta"?Então eu escolheria este:

Evite juntar duplicatas (também conhecidos como produtos cartesianos) devido a junções ao longo de duas ou mais associações paralelas a muitas;use Exists-subqueries, MultiQueries ou FetchMode "subselect" em vez disso.

Tirado de: Dicas de ajuste de desempenho do Hibernate

Só posso limitar minha resposta a uma opção?Nesse caso, eu selecionaria que você implementasse o mecanismo de cache de segundo nível do NHibernate.

Dessa forma, para cada objeto em seu arquivo de mapeamento você poderá definir a estratégia de cache.O cache de segundo nível manterá os objetos já recuperados na memória e, portanto, não fará outra viagem de ida e volta ao banco de dados.Este é um grande impulsionador de desempenho.

Seu objetivo é definir os objetos que são acessados ​​constantemente pela sua aplicação.Entre elas estarão configurações gerais e similares.

Há muitas informações a serem encontradas sobre o cache de segundo nível do nhibernate e como implementá-lo.

Boa sorte :)

Cache, Cache, Cache - Você está usando o cache de primeiro nível corretamente [fechando sessões prematuramente ou usando StatelessSession para ignorar o cache de primeiro nível]?Você precisa configurar um cache simples de segundo nível para valores que mudam com pouca frequência?Você pode armazenar em cache conjuntos de resultados de consultas para acelerar consultas que mudam com pouca frequência?

[Também configuração – você pode definir itens como imutáveis?Você pode reestruturar as consultas para trazer de volta apenas as informações necessárias e transformá-las na entidade original?Será que Batman conseguirá deter o Charada antes que ele chegue à represa?...ah, desculpe, me empolguei.]

A criação de perfil é o primeiro passo - até mesmo simples testes unitários cronometrados - para descobrir onde os maiores ganhos podem ser obtidos

Para coleções, considere definir o tamanho do lote para reduzir o número de instruções selecionadas emitidas - consulte a seção Melhorando a performance para detalhes

Se você ainda não estiver usando o carregamento lento (apropriadamente), comece.Buscar coleções quando você não precisa delas é um desperdício de tudo.

Capítulo Melhorando o desempenho descreve esta e outras maneiras de melhorar o desempenho.

O que muito tempo livre disse.

Leia o Capítulo 19 da documentação, "Melhorando o Desempenho".
Hibernar: http://nhibernate.info/doc/nhibernate-reference/performance.html
Hibernar: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

Use o SQL Profiler (ou equivalente para o banco de dados que você está usando) para localizar consultas de longa duração.Otimize essas consultas com índices apropriados.

Para chamadas de banco de dados usadas em quase todas as páginas de um aplicativo, use CreateMultiQuery para retornar vários conjuntos de resultados de uma única consulta de banco de dados.

E claro, cache.A diretiva OutputCache para páginas/controles.Cache do NHibernate para dados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top