61 Stimmen

Wie lässt sich die Leistung von NHibernate am besten verbessern?

Ich habe eine Anwendung, die NHibernate als ORM verwendet, und manchmal kommt es zu Leistungsproblemen aufgrund der Art und Weise, wie die Daten von ihr abgerufen werden. Was kann man tun, um die Leistung von NHibernate zu verbessern? (Bitte beschränken Sie sich auf eine Empfehlung pro Antwort)

54voto

Chuck Punkte 8172

Das erste und gravierendste Leistungsproblem, das bei NHibernate auftreten kann, ist die Erstellung einer neuen Session Factory für jede erstellte Session. Für jede Anwendungsausführung sollte nur eine Instanz der Sitzungsfabrik erstellt werden, und alle Sitzungen sollten von dieser Fabrik erstellt werden.

In diesem Sinne sollten Sie die gleiche Sitzung so lange verwenden, wie es sinnvoll ist. Dies ist je nach Anwendung unterschiedlich, aber für die meisten Webanwendungen wird eine einzige Sitzung pro Anfrage empfohlen. Wenn Sie Ihre Sitzung häufig wegwerfen, profitieren Sie nicht von den Vorteilen des Sitzungscaches. Ein intelligenter Einsatz des Sitzungscaches kann eine Routine mit einer linearen (oder schlechteren) Anzahl von Abfragen ohne viel Aufwand in eine konstante Anzahl verwandeln.

Ebenso wichtig ist es, dass Sie sicherstellen, dass Sie Ihre Objektreferenzen mit Verzögerung laden. Andernfalls könnten selbst bei den einfachsten Abfragen ganze Objektgraphen geladen werden. Es gibt nur bestimmte Gründe, dies nicht zu tun, aber es ist immer besser, mit "lazy loading" zu beginnen und bei Bedarf zurückzuschalten.

Das bringt uns zu eager fetching, dem Gegenteil von lazy loading. Beim Durchqueren von Objekthierarchien oder beim Durchlaufen von Sammlungen kann man leicht den Überblick über die Anzahl der Abfragen verlieren, so dass man am Ende eine exponentielle Anzahl von Abfragen hat. Eifriges Abrufen kann für jede Abfrage mit einem FETCH JOIN durchgeführt werden. In seltenen Fällen, z. B. wenn es ein bestimmtes Tabellenpaar gibt, das Sie immer abrufen, können Sie das "Lazy Loading" für diese Beziehung deaktivieren.

Wie immer ist der SQL Profiler eine gute Möglichkeit, Abfragen zu finden, die langsam laufen oder wiederholt durchgeführt werden. Bei meiner letzten Tätigkeit hatten wir eine Entwicklungsfunktion, die auch die Abfragen pro Seitenanforderung zählte. Eine hohe Anzahl von Abfragen für eine Routine ist der offensichtlichste Indikator dafür, dass Ihre Routine nicht gut mit NHibernate zusammenarbeitet. Wenn die Anzahl der Abfragen pro Routine oder Anfrage gut aussieht, liegt es wahrscheinlich an der Abstimmung der Datenbank; stellen Sie sicher, dass Sie genügend Speicher haben, um Ausführungspläne und Daten im Cache zu speichern, indizieren Sie Ihre Daten korrekt usw.

Ein kniffliges kleines Problem trat bei SetParameterList() auf. Die Funktion ermöglicht die einfache Übergabe einer Liste von Parametern an eine Abfrage. NHibernate implementiert dies, indem es für jedes übergebene Element einen Parameter erstellt. Dies führt zu einem anderen Abfrageplan für jede Anzahl von Parametern. Unsere Ausführungspläne wurden fast immer aus dem Cache freigegeben. Außerdem können zahlreiche Parameter eine Abfrage erheblich verlangsamen. Wir haben NHibernate so angepasst, dass die Elemente als durch Trennzeichen getrennte Liste in einem einzigen Parameter gesendet werden. Die Liste wurde in SQL Server durch eine Tabellenwertfunktion getrennt, die unser Hack automatisch in die IN-Klausel der Abfrage einfügte. Abhängig von Ihrer Anwendung kann es noch weitere solche Minen geben. SQL Profiler ist der beste Weg, um sie zu finden.

1 Stimmen

Ist NH nicht standardmäßig faul beim Laden von Objektreferenzen? Wenn nicht, was tun Sie, um dies zu erzwingen?

0 Stimmen

@sydneyos Wenn Sie Fluent NHibernate verwenden, können Sie einfach DefaultLazy.Always() als Konvention zu Ihrer Fluent NHibernate-Konfiguration hinzufügen. Ich bin mir nicht sicher, wie das mit .hbm-Mappings funktioniert, aber ich kann mir vorstellen, dass Sie das ziemlich einfach in der NH-Konfiguration hinzufügen können.

26voto

David P Punkte 3594

Die SessionFactory von NHibernate ist eine teure Operation, daher ist es eine gute Strategie, ein Singleton zu erstellen, das sicherstellt, dass nur EINE Instanz der SessionFactory im Speicher vorhanden ist:

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

Dann können Sie es in Ihrer Global.Asax Application_Startup initialisieren:

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

0 Stimmen

+1 für die Bereitstellung eines einfachen Arbeitsbeispiels und einer Erklärung. Ich wünschte, es gäbe eine Funktion, um mehr als 1 für eine gute Antwort zu geben!

11voto

MatthieuGD Punkte 4432

Keine Empfehlung, sondern ein Hilfsmittel für Sie : NH Prof ( http://nhprof.com/ ) scheint vielversprechend zu sein, es kann Ihre Verwendung des ORM-Frameworks bewerten. Es kann ein guter Ausgangspunkt für die Einstellung von NHibernate sein.

1 Stimmen

Ja. Es muss funktionieren, DANN muss es schnell gehen. Und ein Profiler wie NH Prof kann Ihnen die Engpässe aufzeigen.

11voto

Ray Punkte 178277

Vermeiden und/oder minimieren Sie die Wählen Sie N + 1 Problem indem sie erkennt, wann bei langsamen Abfragen von Lazy Loading auf Eager Fetching umgeschaltet werden muss.

0 Stimmen

Keine Einigung über die Lösung. Lazy Loading beibehalten, aber aktivieren Abrufen von Stapeln der trägen Last. Dadurch wird das N+1-Problem mit minimalen Auswirkungen auf den Code beseitigt. Ich habe mehr darüber in meiner Antwort auf eine andere Frage geschrieben aquí .

4voto

Mike Monette Punkte 630

Ohne nähere Angaben zu den Leistungsproblemen, die bei Ihnen auftreten, kann ich nur eine Verallgemeinerung anbieten: Nach meiner Erfahrung sind die meisten Leistungsprobleme bei Datenbankabfragen auf das Fehlen geeigneter Indizes zurückzuführen. Mein Vorschlag für eine erste Maßnahme wäre also, Ihre Abfragepläne auf nicht indizierte Abfragen zu überprüfen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X