Question

J'ai une application qui utilise NHibernate comme ORM et rencontre parfois des problèmes de performances en raison de la manière dont elle a accès aux données. Quelles mesures peuvent être prises pour améliorer les performances de NHibernate? (Veuillez limiter à une recommandation par réponse)

Était-ce utile?

La solution

Le premier et le plus dramatique problème de performances que vous pouvez rencontrer avec NHibernate est la création d’une nouvelle fabrique de sessions pour chaque session créée. 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 la même veine, vous devriez continuer à utiliser la même session tant que cela a du sens. Cela varie selon les applications, 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 que vous souhaitiez vous assurer que vous chargez vos références d'objet. Si vous ne l'êtes pas, des graphiques d'objet complets peuvent être chargés, même pour les requêtes les plus simples. Il n’ya que certaines raisons pour ne pas le faire, mais il est toujours préférable de commencer par un chargement paresseux et de revenir au besoin.

Cela nous amène à chercher avec impatience, le contraire du chargement paresseux. Lorsque vous parcourez des hiérarchies d’objets ou parcourez des collections en boucle, vous pouvez facilement perdre le suivi du nombre de requêtes que vous effectuez et obtenir un nombre exponentiel de requêtes. Une récupération rapide peut être effectuée requête par requête avec un FETCH JOIN. Dans de rares cas, par exemple s'il y a une paire de tables particulière que vous voulez toujours joindre, envisagez de désactiver le chargement paresseux pour cette relation.

Comme toujours, SQL Profiler est un excellent moyen de rechercher des requêtes qui s'exécutent lentement ou qui sont répétées. Lors de mon dernier emploi, nous avions une fonctionnalité de développement qui comptait également les requêtes par 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 obligé de régler la base de données; assurez-vous de disposer de suffisamment de mémoire pour stocker les plans d'exécution et les données dans le cache, indexez correctement vos données, etc.

Un petit problème épineux que nous avons rencontré était avec SetParameterList (). La fonction vous permet de facilement passer une liste de paramètres à une requête. NHibernate a implémenté cela en créant un paramètre pour chaque élément transféré. 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 de la cache. En outre, de nombreux paramètres peuvent considérablement ralentir une requête. Nous avons créé 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 comme celle-ci en fonction de votre application. SQL Profiler est le meilleur moyen de les trouver.

Autres conseils

La SessionFactory de NHibernate étant une opération coûteuse, une bonne stratégie consiste à créer un Singleton qui garantit qu’il n’y ait qu’UNE 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 application Global.Asax Application_Startup, vous pouvez l'initialiser:

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

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

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

Sans aucune précision sur le type de problèmes de performances que vous rencontrez, je ne peux que généraliser: selon mon expérience, la plupart des problèmes de performances des requêtes de base de données résultent d'un manque d'index approprié. Donc, ma suggestion pour une première action serait de vérifier vos plans de requêtes pour les requêtes non indexées.

NHibernate génère du code SQL assez rapide et immédiat. Je l'utilise depuis un an et je n'ai pas encore écrit avec du SQL pur. Tous mes problèmes de performances sont dus à la Normalisation et à l'absence 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é étrangère. Si vous utilisez Microsoft SQL Server, le "Conseiller en optimisation du moteur de base de données" aide beaucoup avec cela.

" Une recommandation par réponse " seulement? Ensuite, je choisirais 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; utiliser les sous-requêtes existantes, les multi-requêtes ou FetchMode "quotelect" à la place.

Extrait de: Conseils de réglage des performances d'Hibernate

Je ne peux que limiter ma réponse à une option? Dans ce cas, je choisirais que vous implémentiez le mécanisme de cache de second niveau de NHibernate.

Ainsi, vous pouvez définir la stratégie de cache pour chaque objet de votre fichier de mappage. 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 vers la base de données. C'est un énorme booster de performance.

Votre objectif est de définir les objets auxquels votre application a constamment accès. Parmi ceux-ci seront les paramètres généraux et similaires.

Il existe de nombreuses informations sur le cache de second niveau nhibernate et sur la manière de le mettre en œuvre.

Bonne chance:)

Mise en cache, mise en cache, mise en cache - Utilisez-vous correctement votre mise en cache de premier niveau [fermeture prématurée de sessions ou utilisez 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 peu fréquemment? Pouvez-vous mettre en cache des ensembles de résultats de requêtes pour accélérer les requêtes qui changent peu souvent?

[Aussi configuration - pouvez-vous définir des éléments immuables? Pouvez-vous restructurer les requêtes pour ne récupérer que les informations dont vous avez besoin et les transformer en 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é.]

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

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

Si vous n'utilisez pas encore le chargement différé, commencez. Aller chercher des collections quand on n'en a pas besoin, c'est tout gâcher.

Le chapitre Amélioration des performances décrit ceci ainsi que d'autres moyens d'améliorer les performances. / p>

Ce que dit beaucoupoffreetime.

Lisez le chapitre 19 de la documentation "Amélioration des performances"

NHibernate: http://nhibernate.info/doc/nhibernate-reference/performance.html
Hibernate: http://docs.jboss.org/ hibernate / core / 3.3 / reference / fr / html / performance.html

Utilisez SQL Profiler (ou l’équivalent pour la base de données utilisée) pour localiser les requêtes de longue durée. Optimisez ces requêtes avec les 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 ensembles de résultats à partir d'une requête de base de données unique.

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top