61 votes

Quelle est la meilleure façon d'améliorer les performances de NHibernate ?

J'ai une application qui utilise NHibernate comme ORM et qui connaît parfois des problèmes de performance en raison de la façon dont elle accède aux données. Quelles sont les mesures à prendre pour améliorer les performances de NHibernate (veuillez vous limiter à une recommandation par réponse) ?

53voto

Chuck Points 6314

Le premier et le plus grave problème de performance que vous pouvez rencontrer avec NHibernate est si vous créez une nouvelle fabrique de session pour chaque session que vous créez. Une seule instance de fabrique de sessions doit être créée pour chaque exécution d'application et toutes les sessions doivent être créées par cette fabrique.

Dans le même ordre d'idées, vous devriez continuer à utiliser la même session tant que cela a un sens. Cela varie selon les applications, mais pour la plupart des applications Web, il est recommandé d'utiliser une seule session par demande. Si vous jetez votre session fréquemment, vous ne profitez pas des avantages de son cache. Une utilisation intelligente du cache de session peut transformer une routine avec un nombre linéaire (ou pire) de requêtes en un nombre constant sans beaucoup de travail.

Il est tout aussi important de s'assurer que vous chargez vos références d'objets paresseusement. Si vous ne le faites pas, des graphes entiers d'objets pourraient être chargés, même pour les requêtes les plus simples. Il n'y a que certaines raisons de ne pas le faire, mais il est toujours préférable de commencer par un chargement paresseux et de revenir en arrière si nécessaire.

Cela nous amène à la récupération rapide, l'opposé du chargement paresseux. Lorsque vous traversez des hiérarchies d'objets ou que vous bouclez des collections, il est facile de perdre le compte du nombre de requêtes que vous effectuez et vous vous retrouvez avec un nombre exponentiel de requêtes. L'extraction rapide peut être effectuée sur une base par requête avec un FETCH JOIN. Dans de rares circonstances, par exemple s'il y a une paire de tables particulière que vous rejoignez toujours par récupération, envisagez de désactiver le chargement paresseux pour cette relation.

Comme toujours, SQL Profiler est un excellent moyen de trouver les requêtes qui s'exécutent lentement ou qui sont faites de manière répétée. Dans mon dernier emploi, nous avions une fonction de développement qui comptait également les requêtes par demande de page. Un nombre élevé de requêtes pour une routine est l'indicateur le plus évident que votre routine ne fonctionne pas bien avec NHibernate. Si le nombre de requêtes par routine ou par demande semble bon, vous en êtes probablement réduit au réglage de la base de données ; assurez-vous que vous avez suffisamment de mémoire pour stocker les plans d'exécution et les données dans le cache, indexez correctement vos données, etc.

Nous avons rencontré un petit problème délicat avec SetParameterList(). Cette fonction vous permet de passer facilement une liste de paramètres à une requête. NHibernate l'implémente en créant un paramètre pour chaque élément passé. Il en résulte un plan de requête différent pour chaque nombre de paramètres. Nos plans d'exécution étaient presque toujours libérés du cache. En outre, de nombreux paramètres peuvent ralentir considérablement une requête. Nous avons fait une modification personnalisée de NHibernate pour envoyer les éléments sous forme de liste délimitée dans un seul paramètre. La liste était séparée dans SQL Server par une fonction de valeur de table que notre hack a automatiquement insérée dans la clause IN de la requête. Il peut y avoir d'autres mines terrestres comme celle-ci en fonction de votre application. SQL Profiler est le meilleur moyen de les trouver.

26voto

David P Points 2430

SessionFactory de NHibernate est une opération coûteuse. Une bonne stratégie consiste donc à créer un Singleton qui garantit qu'il n'y a qu'UNE seule instance de SessionFactory en mémoire :

   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();
        }
    }

Ensuite, dans votre Global.Asax Application_Startup, vous pouvez l'initialiser :

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

11voto

Ray Vega Points 30187

Éviter et/ou minimiser les Sélectionner le problème N + 1 en reconnaissant quand il faut passer du chargement paresseux à l'extraction rapide pour les requêtes à faible rendement.

11voto

Matthieu Points 2766

Ce n'est pas une recommandation mais un outil pour vous aider : NH Prof ( http://nhprof.com/ ) semble être prometteur, il peut évaluer votre utilisation du framework ORM. Il peut être un bon point de départ pour votre mise au point de NHibernate.

4voto

Mike Monette Points 370

En l'absence de précisions sur le type de problèmes de performances que vous rencontrez, je ne peux que proposer une généralisation : D'après mon expérience, la plupart des problèmes de performance des requêtes de base de données sont dus à l'absence d'indices appropriés. Je vous suggère donc de commencer par vérifier vos plans de requête pour les requêtes non indexées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X