it-swarm.com.de

Ist es WIRKLICH möglich, dass die Reihenfolge für diese bestimmte redundante abgeleitete Tabelle nicht garantiert wird?

Ich bin auf diese Frage bei einem Twitter-Gespräch mit Lukas Eder gestoßen.

Obwohl das richtige Verhalten darin besteht, die ORDER BY-Klausel auf die äußerste Abfrage anzuwenden, verwenden wir hier keine DISTINCT-, GROUP BY-, JOIN- oder andere WHERE-Klausel in der äußersten Abfrage. Warum sollte ein RDBMS nicht einfach die Klausel übergeben? eingehende Daten, wie sie nach der inneren Abfrage sortiert wurden?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

Wenn Sie dieses Beispiel zumindest unter PostgreSQL ausführen, erhalten Sie denselben Ausführungsplan sowohl für die innere Abfrage als auch für dieses Beispiel für abgeleitete Tabellen sowie dieselbe Ergebnismenge.

Ich würde also davon ausgehen, dass der Planer die äußerste Abfrage einfach verwirft, weil sie redundant ist, oder einfach die Ergebnisse aus der inneren Tabelle durchläuft.

Glaubt jemand, dass dies möglicherweise nicht der Fall ist?

12
Vlad Mihalcea

Die meisten Datenbanken sind sich ziemlich klar darüber, dass ein ORDER BY In einer Unterabfrage entweder:

  • Nicht erlaubt: z. SQL Server, Sybase SQL Anywhere (sofern nicht mit TOP oder OFFSET .. FETCH Ergänzt)
  • Bedeutungslos: z.B. PostgreSQL, DB2 (wieder, sofern nicht mit OFFSET .. FETCH Oder LIMIT ergänzt)

Hier ist ein Beispiel aus dem DB2 LUW-Handbuch (Schwerpunkt Mine)

Eine ORDER BY-Klausel in einer Unterauswahl hat keinen Einfluss auf die Reihenfolge der Zeilen, die von einer Abfrage zurückgegeben werden. Eine ORDER BY-Klausel wirkt sich nur auf die Reihenfolge der zurückgegebenen Zeilen aus, wenn sie in der äußersten vollständigen Auswahl angegeben ist.

Der Wortlaut ist ziemlich explizit, genau wie bei PostgreSQL :

Wenn die Sortierung nicht ausgewählt ist, werden die Zeilen in einer nicht angegebenen Reihenfolge zurückgegeben. Die tatsächliche Reihenfolge hängt in diesem Fall von den Scan- und Join-Plan-Typen und der Reihenfolge auf der Festplatte ab aber es darf nicht darauf vertraut werden. Eine bestimmte Ausgabereihenfolge kann nur garantiert werden, wenn der Sortierschritt explizit ausgewählt wird.

Aus dieser Spezifikation kann geschlossen werden, dass jede Reihenfolge, die sich aus der ORDER BY - Klausel in einer abgeleiteten Tabelle ergibt, nur zufällig ist und zufällig mit Ihrer erwarteten Reihenfolge übereinstimmt (was in den meisten Datenbanken in Ihrem trivialen Beispiel der Fall ist), aber es ist wäre unklug, sich darauf zu verlassen.

Randnotiz zu DB2:

Insbesondere DB2 hat eine weniger bekannte Funktion namens ORDER BY ORDER OF <table-designator> , die wie folgt verwendet werden kann:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

In diesem speziellen Fall kann die Reihenfolge der abgeleiteten Tabelle explizit Im äußersten SELECT wiederverwendet werden

Randnotiz zu Oracle:

In Oracle ist es seit Jahren üblich, die Paginierung OFFSET mit ROWNUM zu implementieren, die nur nach dem Zufallsprinzip berechnet werden kann nach eine abgeleitete Tabelle bestellen:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

Es ist zu erwarten, dass zumindest in Gegenwart von ROWNUM in einer Abfrage zukünftige Oracle-Versionen dieses Verhalten nicht aufheben, um nicht so ziemlich das gesamte ältere Oracle SQL zu brechen, das noch nicht migriert wurde zur viel wünschenswerteren und lesbareren SQL-Standardsyntax OFFSET .. FETCH:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
20
Lukas Eder

Ja. Ohne ein ORDER BY Klausel Die Ausgabereihenfolge ist undefiniert und der Abfrageplaner kann davon ausgehen, dass Sie dies wissen und verstehen.

Es kann sein, dass die äußere Abfrage, da sie keine Reihenfolge angibt, die Reihenfolge in der inneren Abfrage löschen kann, um eine Sortieroperation zu vermeiden, insbesondere wenn kein Clustered-Index oder überhaupt kein Index zur Unterstützung der Reihenfolge vorhanden ist. Wenn dies jetzt nicht der Fall ist , kann dies in zukünftigen Versionen der Fall sein.

Verlassen Sie sich niemals auf undefiniertes Verhalten. Wenn Sie eine bestimmte Bestellung benötigen, geben Sie ein ORDER BY Klausel an der entsprechenden Stelle.

12
David Spillett

Es ist genau das Problem mit undefiniertem Verhalten - funktioniert für Sie, funktioniert für mich, formatiert die Festplatte in prod neu;)

Wir können einen Schritt zurücktreten und sagen, dass Sie in gewissem Sinne Recht haben - es gibt keinen irdischen Grund, warum ein vernünftiges RDBMS die Zeilen in der inneren Auswahl neu anordnen würde. Aber es ist nicht garantiert - was bedeutet, dass es in Zukunft einen Grund geben kann, und es steht den Anbietern frei, dies zu tun. Dies bedeutet, dass jeder Code, der sich auf dieses Verhalten stützt, einer Änderung ausgeliefert ist, die ein Anbieter vornehmen könnte und zu deren Veröffentlichung er nicht verpflichtet wäre, da es sich nicht um eine brechende Änderung eines API-POV handelt.

6
PaulJWilliams

Ist es WIRKLICH möglich, dass die Reihenfolge für diese bestimmte redundante abgeleitete Tabelle nicht garantiert wird?

Die Antwort für alle derzeit vorhandenen Postgres (die Sie getestet haben) Versionen lautet: Nein - für diese spezielle Abfrage. Sortierreihenfolge ist garantiert.

SQL Server-Benutzer werden sich damit unwohl fühlen, da Microsoft nicht einmal ORDER BY In Unterabfragen zulässt. Die Sortierreihenfolge ist für diese einfache Abfrage in Postgres dennoch garantiert. ORDER BY Wird in der Unterabfrage angewendet, und die äußere Abfrage führt nichts aus, was die Reihenfolge ändern könnte.

Das Handbuch weist sogar auf so viel im Kapitel Aggregate Functions hin :

Alternativ funktioniert normalerweise die Angabe der Eingabewerte aus einer sortierten Unterabfrage.

Beachten Sie, dass dies nur zutrifft, wenn äußere Abfrageebenen keine Vorgänge hinzufügen, die die Reihenfolge ändern könnten. Es ist also nur für den einfachen Fall "garantiert" und wird nicht vom SQL-Standard unterstützt. Postgres kann nachbestellt werden, wenn zusätzliche Operationen möglich sind. Im Zweifelsfall fügen Sie dem äußeren SELECT ein weiteres ORDER BY Hinzu. (In diesem Fall wäre das innere ORDER BY Redundantes Rauschen für diese einfache Abfrage.)

2