it-swarm-fr.com

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

J'ai une application qui utilise NHibernate comme ORM et parfois elle rencontre des problèmes de performances en raison de la façon dont les données sont accessibles par elle. Quel genre de choses peut-on faire pour améliorer les performances de NHibernate? (Veuillez limiter à une recommandation par réponse)

61
Ray Vega

Le premier et le plus dramatique problème de performances que vous pouvez rencontrer avec NHibernate est si vous créez une nouvelle fabrique de sessions 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 ce sens, vous devez continuer à utiliser la même session aussi longtemps que cela a du sens. Cela variera selon l'application, mais pour la plupart des applications Web, une seule session par demande est recommandée. Si vous jetez fréquemment votre session, vous ne bénéficiez pas des avantages de son cache. L'utilisation intelligente du cache de session peut changer une routine avec un nombre linéaire (ou pire) de requêtes en un nombre constant sans trop de travail.

Il est tout aussi important de vous assurer que vous êtes paresseux lors du chargement de vos références d'objet. Si vous ne l'êtes pas, des graphiques d'objets entiers 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 à une récupération avide, à l'opposé du chargement paresseux. En parcourant les hiérarchies d'objets ou en parcourant les collections, il peut être facile de perdre la trace du nombre de requêtes que vous effectuez et vous vous retrouvez avec un nombre exponentiel de requêtes. La récupération désirée peut être effectuée par requête avec un FETCH JOIN. Dans de rares circonstances, comme s'il y a une paire particulière de tables que vous récupérez toujours, joignez-vous à la désactivation du chargement différé pour cette relation.

Comme toujours, SQL Profiler est un excellent moyen de rechercher des requêtes qui s'exécutent lentement ou sont répétées. Lors de mon dernier travail, nous avions une fonctionnalité 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 demande semble bon, vous êtes probablement à l'optimisation de la base de données; s'assurer que vous disposez de suffisamment de mémoire pour stocker les plans d'exécution et les données dans le cache, indexer correctement vos données, etc.

Un petit problème délicat que nous avons rencontré était avec SetParameterList (). La fonction vous permet de passer facilement une liste de paramètres à une requête. NHibernate a implémenté cela en créant un paramètre pour chaque élément transmis. 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. De plus, de nombreux paramètres peuvent ralentir considérablement une requête. Nous avons fait un hack personnalisé de NHibernate pour envoyer les éléments sous forme de liste délimitée dans un seul paramètre. La liste a été 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 pourrait y avoir d'autres mines terrestres comme celle-ci selon votre application. SQL Profiler est le meilleur moyen de les trouver.

53
Chuck

La SessionFactory de NHibernate est une opération coûteuse, donc une bonne stratégie consiste à 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();
}
26
David P

Évitez et/ou minimisez le Sélectionnez le problème N + 1 en reconnaissant quand passer du chargement paresseux au chargement rapide pour les requêtes à exécution lente.

11
Ray Vega

Pas une recommandation mais un outil pour vous aider: NH Prof ( http://nhprof.com/ ) semble prometteur, il peut évaluer votre utilisation du framework ORM. Cela peut être un bon point de départ pour votre tunning de NHibernate.

10
MatthieuGD

Sans aucun détail sur les types de problèmes de performances que vous voyez, je ne peux que proposer une généralisation: D'après mon expérience, la plupart des problèmes de performances des requêtes de base de données proviennent du manque d'indices appropriés. Donc, ma suggestion pour une première action serait de vérifier vos plans de requête pour les requêtes non indexées.

4
Mike Monette

"Une seule recommandation par réponse" seulement? Ensuite, j'irais pour celui-ci:

Évitez les doublons de jointure (produits cartésiens AKA) en raison des jointures le long de deux ou plusieurs associations parallèles à plusieurs; utilisez plutôt les sous-requêtes Exists, MultiQueries ou FetchMode "subselect".

Extrait de: Hibernate Performance Tuning Tips

3
gnome26

NHibernate génère un SQL assez rapide dès la sortie de la boîte. Je l'utilise depuis un an et je n'ai pas encore eu à écrire du SQL brut avec. Tous mes problèmes de performances provenaient de Normalisation et du manque d'index.

La solution la plus simple consiste à examiner les plans d'exécution de vos requêtes et à créer des index appropriés, en particulier sur vos colonnes de clés étrangères. Si vous utilisez Microsoft SQL Server, le "Database Engine Tuning Advisor" aide beaucoup avec cela.

3
Eric Lathrop

Je n'ai le droit de limiter ma réponse qu'à une seule option? Dans ce cas, je choisirais d'implémenter le mécanisme de cache de deuxième niveau de NHibernate.

De cette façon, pour chaque objet de votre fichier de mappage, vous pouvez définir la stratégie de cache. Le cache de second niveau gardera en mémoire les objets déjà récupérés et ne fera donc pas un autre aller-retour dans la base de données. Il s'agit d'un énorme booster de performances.

Votre objectif est de définir les objets auxquels votre application accède en permanence. Parmi ceux-ci, il y aura les paramètres généraux et autres.

Il y a beaucoup d'informations à trouver sur le cache de deuxième niveau nhibernate et comment l'implémenter.

Bonne chance :)

1
Hace

Le profilage est la première étape - même de simples tests unitaires chronométrés - pour savoir où les gains les plus importants peuvent être réalisés

Pour les collections, pensez à définir la taille du lot pour réduire le nombre d'instructions sélectionnées émises - voir la section Amélioration des performances pour plus de détails

1
Richard

Si vous n'utilisez pas déjà le chargement différé (de manière appropriée), commencez. Récupérer des collections lorsque vous n'en avez pas besoin est un gaspillage de tout.

Chapitre Amélioration des performances décrit cela et d'autres façons d'améliorer les performances.

1
lotsoffreetime

Mise en cache, mise en cache, mise en cache - Utilisez-vous correctement la mise en cache de premier niveau [fermeture prématurée des sessions ou utilisation de StatelessSession pour contourner la mise en cache de premier niveau]? Avez-vous besoin de configurer un cache de second niveau simple pour les valeurs qui changent rarement? Pouvez-vous mettre en cache des ensembles de résultats de requête pour accélérer les requêtes qui changent rarement?

[Également configuration - pouvez-vous définir des éléments comme immuables? Pouvez-vous restructurer des requêtes pour ne récupérer que les informations dont vous avez besoin et les transformer en l'entité d'origine? Batman pourra-t-il arrêter le Riddler avant qu'il n'atteigne le barrage? ... oh, désolé, je me suis emporté.]

1
Watson

Qu'est-ce que lotsoffreetime a dit.

Lisez le chapitre 19 de la documentation, "Amélioration des performances".
NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
Hibernation: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

Utilisez SQL Profiler (ou équivalent pour la base de données que vous utilisez) pour localiser les requêtes de longue durée. Optimisez ces requêtes avec des index appropriés.

Pour les appels de base de données utilisés sur presque toutes les pages d'une application, utilisez CreateMultiQuery pour renvoyer plusieurs jeux de résultats à partir d'une seule requête de base de données.

Et bien sûr, cache. La directive OutputCache pour les pages/contrôles. NHibernate cache pour les données.

0
Axl