2012-03-28 10 views
2

Wir haben ein Datenraster, um Mitglieder Datensätze für unsere Kunden anzuzeigen. Wir wurden kürzlich damit beauftragt, unsere Anwendung um Paging zu erweitern, so dass unsere großen Kunden (500.000+ Mitglieder).fließende Nhibernate-Abfrage dauert eine lange Zeit, um eine zugeordnete Formel mit Paging zu sortieren

Unsere Tabelle, aus der wir die Daten entnehmen, hat 10 Spalten. Wenn unsere Daten in unsere Anwendung ziehen fügten wir drei zusätzliche Spalten, die alle berechneten Felder sind

dh

SELECT SUM(tableX.Cost) FROM tableX WHERE tableX.ID = this_.ID 

wo „this_“ ist der Alias ​​für unsere Mitglieder Tisch und TableX stellt die andere Tabelle, die wir brauchen, um Grab Daten von.

In unserer Abfrage müssen wir bieten die Möglichkeit, die Spalten zu bestellen, aber ich habe festgestellt, dass, wenn ich versuche, die berechneten Felder zu bestellen, dass es eine erhebliche Menge an Zeit im Vergleich zu, wenn ich ORDER BY eine Spalte in Der Tisch. Dies macht zwar Sinn, dass es länger dauert, aber wenn es nur ein paar Minuten dauert, um nur 1000 Datensätze zu laden, wird es mehr als 500 Seiten geben. Dann fühle ich, dass das Ausrufen sinnlos macht.

Ich habe ein bisschen in vielleicht einen Second-Level-Cache mit Nhibernate, aber aus was ich bisher gelesen habe ich bin mir nicht sicher, ob dieses Problem lösen wird.

Durch die Art und Weise eine der Karten ist:

Map(x => x.Cost) 
    .Formula(@"(SELECT SUM(_Claims.Cost) FROM _Claims WHERE _Claims.ID = this_.ID") 
    .Nullable(); 

und für die Abfrage

var list = CurrentSession() 
       .SetFirstRsult(startPos) 
       .SetMaxResults(1000) 
       .SetTimeout(100) 
       .Add(Restrictions.Eq("ClientID", _clientID)); 

    if(isASC) 
    { 
     list.AddOrder(Order.Asc(Projetions.Property(_propertyString))); 
    } 
    else 
    { 
     list.AddOrder(Order.Desc(Projetions.Property(_propertyString))); 
    } 

    return list.List<Member>(); 

ich die Ideen für diese ausgeführt wird. Wenn uns also jemand in die richtige Richtung weist, würde ich das sehr schätzen.

Dank

+0

Können Sie eine Ansicht für Ihre berechneten Felder erstellen? Es klingt wie beim Sortieren, indem das Recordset heruntergefahren wird, die berechneten Felder zugeordnet und hinzugefügt werden und dann auf dem Client sortiert wird. Das Erstellen einer Ansicht würde sicherstellen, dass Sie auf dem Server sortieren. – jlnorsworthy

+0

Ich glaube, dass es auf dem Server basierend auf der Abfrage sortiert, die NHibernate generiert. Ich denke, ich bin mir nicht sicher, wie es auf dem Client sein könnte, weil ich nicht denke, NH würde ~ 500.000 Datensätze greifen und sortieren dann die Top 1000 Datensätze zwischen den Reihen X und Y. – CSMHowitzer

+0

Auch Blick auf Ihren Vorschlag Vorschlag ich don Ich denke, das ist eine ideale Lösung, denn das würde bedeuten, dass wir für jeden einzelnen unserer Kunden einen Überblick haben müssen, da wir einen Parameter nicht in eine Ansicht übertragen können. Wieder denke ich, dass es auf dem Server sortiert ist. – CSMHowitzer

Antwort

3

Dies ist eigentlich nicht so sehr ein NHibernate Problem, sondern ein allgemeines SQL Problem.

Natürlich ist es auf dem Server sortiert, aber die Summe wird für alle Datensätze berechnet, bevor sie sortiert werden können. Sie sollten dies überprüfen können, indem Sie einen SQL-Profiler verwenden oder eine SQL-Funktion/Prozedur erstellen, die die Summe berechnet und diese in Ihre Abfrage einfügt und dann überprüft, wie oft sie aufgerufen wird. Wenn Sie einen Tisch mit 500.000+ Mitgliedern haben, wird es 500.000+ Mal genannt; Es gibt einfach keinen anderen Weg.

Was Sie könnten versuchen, ist dies:

  1. Achten Sie darauf, einen Index für Claims.ID verwenden (ein Fremdschlüssel funktioniert der Trick).
  2. Kopieren & Fügen Sie die generierte SQL und führen Sie es direkt in der Datenbank und sehen, ob das lange dauert.
  3. Wenn es Ihnen nichts ausmacht, irgendeine Art von Redundanz zu haben, können Sie neue Spalten für die berechneten Felder in Ihrer Members Tabelle hinzufügen und Trigger (Einfügen/Löschen) in der Tabelle verwenden, um diese Spalten entsprechend zu aktualisieren.
  4. Wenn Sie keine Trigger verwenden möchten, können Sie auch ein zeitgesteuertes Datenbankereignis erstellen, um die Berechnung durchzuführen. (Dies ist natürlich nur eine Option, wenn Sie keine Echtzeitdaten benötigen).
+0

Ich muss das von meinem Team ausführen. Das scheint sehr interessant zu sein. Ja, indem Sie das generierte SQL ausführen, hat es auch einige Zeit gedauert und wie Sie gesagt haben, liegt es daran, dass es alle Datensätze durchlaufen muss. Ich werde das aktualisieren, nachdem wir es an unserem Ende herausgefunden haben. – CSMHowitzer

+0

Wir werden das nicht implementieren. Der Hauptgrund ist, dass wir zwei Server haben, einer ist Produktion und der andere ist Entwickler. Unser Produktionsserver hat unsere Zeiten dramatisch verkürzt. Wenn wir viel mehr Kunden mit viel mehr Mitgliedern bekommen, werden wir dieses Problem wieder lösen, aber wir sind ein kleines Team. Also denke ich, wir werden nur damit aufhören. – CSMHowitzer

+2

Punkt 5: Bei Verwendung eines ORM können Redundanzen in den Entitäten leicht berechnet werden. Dies macht es transparenter und vermeidet jede dieser datenbankspezifischen Technologien. (Mehr testbar, tragbar, wartbar ...) –

0
  1. Die erste Option wäre, die Daten vorauszuberechnen und haben sie bereit, aus einer Tabelle zu einem Data Transfer Object
  2. Erstellen Sie eine Ansicht und Karte abgefragt werden. In der Ansicht können Sie zunächst den Datensatz einschränken und dann die Berechnung durchführen. Weniger Daten zur Berechnung führen dazu, dass Ihre Abfrage schneller ausgeführt wird.