2016-06-10 25 views
2

Ich habe seit Jahren den gleichen Teil der sql Paginierung Code .. und ich habe jetzt nur diese Kuriosität bemerkt .. Ich denke, es ist ziemlich interessant, und wir sollten darüber diskutieren . Also hier ist die Standard-Paginierung Boilerplate:sql Paginierung wenn 'bestellen von' nicht-deterministisch

SELECT a.* 
    FROM (SELECT b.*, 
       rownum b_rownum 
      FROM (SELECT c.* 
        FROM some_table c 
       ORDER BY some_column) b 
     WHERE rownum <= <<upper limit>>) a 
WHERE b_rownum >= <<lower limit>>` 

was funktioniert fantastisch, wenn einige Spalte sequenziell ist.

aber ich mache dies frei und erlaubt dem Benutzer nach jeder Spalte zu sortieren, und wenn sie zufällig eine Spalte auswählen, die die gleichen Werte enthält, bricht die Seitennummerierung ab.

das heißt, die Abfrage wird die gleiche genaue Zeile Datenseite nach Seite zurückgeben. Und wenn ich darüber nachdenke, warum nicht? es wählt wahrscheinlich nur die schnellsten Zeilen oder was auch immer, die den Filter passieren.

so zum Beispiel, geben diese SQL exakt die gleichen Daten

select * 
from (select a.*, ROWNUM rnum 
     from (select * from xsd order by PREFIX asc) a 
     where ROWNUM <= 30 
    ) 
where rnum >= 20; 


select * 
from (select a.*, ROWNUM rnum 
     from (select * from xsd order by PREFIX asc) a 
     where ROWNUM <= 40 
    ) 
where rnum >= 30; 

meist nur, dass ich dachte, das war ordentlich & ich nicht viel gesehen haben über diese Nebenwirkung in anderen Beiträgen.

Und auch, ich fragte mich, was ich dagegen tun könnte .. und wenn andere Strategie Verarbeitungszeit hinzufügen würde.

SOLUTION von Gordon, Alex

fügen Sie einfach den Rowid als Standard endgültige Reihenfolge durch. Diese SQL ist jetzt anders. Ich habe nicht bemerkt jede Veränderung in der Antwortzeit

select * 
from (select a.*, ROWNUM rnum 
     from (select * from xsd order by PREFIX asc, rowid) a 
     where ROWNUM <= 30 
    ) 
where rnum >= 20; 


select * 
from (select a.*, ROWNUM rnum 
     from (select * from xsd order by PREFIX asc, rowid) a 
     where ROWNUM <= 40 
    ) 
where rnum >= 30; 

ein weiterer Sieg für Stackoverflow, dank gentelmen, glücklich Codierung jeder

+0

Markieren Sie die verwendeten dbms. Fügen Sie einige Beispieltabellendaten und ein altes vs. neues Ergebnis hinzu. – jarlh

+0

Ich habe ein Orakel-Tag hinzugefügt, ja, ich kann leicht einige Vorher-Nachher-Zeiten angeben. Das Einzige, was man über die Daten wissen muss, ist, dass es Tausende von 'PREFIX' mit demselben Wert gibt. –

Antwort

5

SQL-Tabellen ungeordnete Sätze darstellen. Als Konsequenz sind SQL-Sortierungen nicht stabil. Das bedeutet, dass Zeilen mit denselben Schlüsselwerten in beliebiger Reihenfolge vorliegen können - und bei mehreren Durchläufen kann sich die Reihenfolge ändern. Es gibt keine "zugrunde liegende" Reihenfolge für die Zeilen.

Die Lösung besteht darin, eine eindeutige ID am Ende der order by hinzuzufügen. Dies wäre immer der letzte Schlüssel:

Ob dies Auswirkungen auf die Leistung hat, hängt davon ab, ob Indizes für die Sortierung verwendet werden können. Wenn keine Indizes verwendet werden, sollte der Effekt sehr gering sein. Wenn das Hinzufügen des zusätzlichen Schlüssels jedoch verhindert, dass ein Index verwendet wird, ist der Einfluss viel größer.

+0

hmm, also sollte ich einfach meine eigene "id" -Spalte machen und diese als versteckten Standard 'order by' verwenden? vielleicht könnte ich etwas mit einer Sequenz tun, wie 'in emp (empno) -Werte einfügen (mySeq.nextVal);' –

+1

@SteveRenyolds - wenn du noch keinen eindeutigen Schlüssel hast (obwohl du angedeutet hast, dass einige der Spalten einzigartig sind?) Vielleicht könnten Sie Rowid verwenden, anstatt eine zusätzliche Dummy-Spalte hinzuzufügen. Es ist nicht ganz stabil, aber könnte hier gut genug funktionieren. Wenn Sie eine Tabelle und nicht eine Ansicht abfragen. –