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


11

Ich bin auf diese Frage in 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?


4
Beachten Sie, dass Ihre Abfrage in SQL Server fehlschlägt, da eine Reihenfolge nach in einer abgeleiteten Tabelle nicht zulässig ist.
a_horse_with_no_name

Warum bist du so ungläubig? Warum würden Sie etwas annehmen? Wenn Sie ein Programm schreiben, das Ihnen die Wahl lässt, erwarten Sie, dass Benutzer Dinge über Ihre Wahl erwarten? Lesen Sie mehr über die Optimierung / Implementierung logischer und physischer Abfragen.
Philipxy

2
"Ich würde 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." Sie können genauso gut davon ausgehen, dass der Planer die Bestellklausel in der inneren Abfrage verwirft , da sie im Kontext bedeutungslos ist.
Wildcard

MariaDB, ungefähr 2012, diskutiert das Thema. Das Fehlen des InnerenORDER BYführt zu einer unterschiedlichen Optimierung für gruppenweise max .
Rick James

1
Eigentlich sind Sie richtig für Postgres.
Erwin Brandstetter

Antworten:


19

Die meisten Datenbanken sind sich ziemlich klar darüber, dass eine ORDER BYin einer Unterabfrage entweder:

  • Nicht erlaubt: zB SQL Server, Sybase SQL Anywhere (sofern nicht mit TOPoder ergänzt OFFSET .. FETCH)
  • Sinnlos: zB PostgreSQL, DB2 (wieder, sofern nicht mit OFFSET .. FETCHoder ergänzt LIMIT)

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 von einer Abfrage zurückgegebenen Zeilen . 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-Planarten und der Reihenfolge auf der Festplatte ab, darf jedoch nicht als zuverlässig angesehen 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 BYKlausel 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 wäre unklug, sich darauf zu verlassen Dies.

Randnotiz zu DB2:

Insbesondere hat DB2 eine weniger bekannte Funktion namensORDER 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 im äußersten SELECT explizit wiederverwendet werden

Randnotiz zu Oracle:

In Oracle ist es seit Jahren üblich, die OFFSETPaginierung mithilfe von zu implementieren ROWNUM, die nur nach Bestellung einer abgeleiteten Tabelle angemessen berechnet werden kann :

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 ROWNUMzukünftige Oracle-Versionen zumindest bei Vorhandensein einer Abfrage dieses Verhalten nicht aufheben, um nicht so ziemlich das gesamte ältere Oracle SQL zu brechen, das noch nicht auf das viel wünschenswertere und umgestiegene Oracle SQL umgestellt wurde lesbare SQL-Standardsyntax OFFSET .. FETCH:

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

Meaningless: E.g. PostgreSQLsollte wirklich: ‚unzuverlässig‘, weil es tut etwas bedeuten. Zeilen werden in der inneren Abfrage sortiert, und diese Reihenfolge wird in den äußeren Abfrageebenen beibehalten, sofern nicht anders angegeben oder eine Neuordnung für zusätzliche Vorgänge angebracht ist. Auch wenn dies nur ein Implementierungsdetail ist, ist es nicht bedeutungslos. Dies kann für sortierte Eingaben verwendet werden, um Funktionen zu aggregieren. Das Handbuch weist sogar darauf hin: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter

Das Zitat, das Sie für Postgres hinzugefügt haben, gilt tatsächlich für einen anderen Fall: Abfragen ohne Nein ORDER BY.
Erwin Brandstetter

@ErwinBrandstetter: Fühlen Sie sich frei, eine Antwort mit diesen Details hinzuzufügen. Ich persönlich bin nicht der Meinung, dass Implementierungsdetails von Bedeutung sind. Erst heute habe ich erfahren, dass sich die Leute früher darauf verlassen haben, dass Oracle in Oracle 8i (glaube ich) immer eine sortierte Gruppe nach Operation ausführt, als plötzlich eine neuere Version eine Hash-Gruppe von einführte, die die Annahme brach, dass einige implizit sind auf die Bestellung kann man sich verlassen. Mit anderen Worten: Ich mag es, es in fetten Worten auszudrücken. Sinnlos , anstatt oh, wenn Sie die komplizierten Details der Version xyz kennen, können Sie tatsächlich ...
Lukas Eder

Ich habe bereits eine Antwort hinzugefügt. Ob wir nicht standardmäßiges Verhalten ignorieren oder welche anderen guten Ratschläge wir haben, steht neben der Frage: Ist die Reihenfolge für die angegebene Anfrage garantiert? Es ist für Postgres. Es ist nicht (oder nicht einmal anwendbar) für andere RDBMS. Und das gilt für alle vorhandenen Versionen von Postgres, nicht nur für die Version xyz. Es ist sogar dokumentiert (mit Vorbehalt). Ihr Zitat ist irreführend. Wenn wir nicht standardmäßiges Verhalten ignorieren möchten, beginnen wir möglicherweise mit Oracle, sodass wir glauben, dass NULL und die leere Zeichenfolge identisch sind. Auch orthogonal zur Frage.
Erwin Brandstetter

@ErwinBrandstetter: Interessant, danke für das Update. Ist diese Garantie, auf die Sie sich beziehen, dokumentiert?
Lukas Eder

12

Ja. Ohne eine ORDER BYKlausel ist die Ausgabereihenfolge 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 an ORDER BYder entsprechenden Stelle eine Klausel an.


Beim Testen unter PostgreSQL wurde die Sortierung nach einem sequentiellen Scan durchgeführt, da ich keinen Index für die von ORDER BY verwendete Spalte hatte. Welches RDBMS überspringt Ihrer Meinung nach die innere Abfrage ORDER BY?
Vlad Mihalcea

5
Ich kann nicht sagen, dass ich weiß, was wird , nur dass sie alle vollkommen frei sind, dies zu tun, wenn sie es wünschen - es wäre eine vollkommen akzeptable Optimierung sowohl nach den allgemeinen Standards als auch nach den Produktspezifikationen. SQL Server lehnt die Abfrage sofort ab (es sei denn, Sie geben an, TOP 100%dass die aktuelle Abfrage nicht portierbar ist, sollte dies eine Priorität für Ihr Projekt sein. Da Postgres die Reihenfolge in der inneren Abfrage jetzt befolgt, bedeutet dies nicht, dass dies in Zukunft immer der Fall sein wird (oder dass ältere Versionen dies tatsächlich tun), so dass Sie es vermeiden sollten, sich für alle Fälle auf das Verhalten zu verlassen.
David Spillett

1
@VladMihalcea Ein DBMS, das die Redundanz "wegoptimiert", ORDER BYist MariaDB: Warum wird ORDER BY in einer FROM-Unterabfrage ignoriert?
Ypercubeᵀᴹ

6

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.


2
Der einzige Grund, warum die Reihenfolge dadurch optimiert werden kann, ist die Geschwindigkeit. Das Zurückgeben der Zeilen in einer anderen Reihenfolge kann effizienter sein.
TomTom

2
Insbesondere kann der Server Parallelität ausnutzen, um die Tabelle zu lesen. Wenn dies der Fall ist und Sie keine Reihenfolge erzwingen müssen, erhalten Sie die Zeilen zurück, obwohl die Threads sie lesen. (SQL Server tut dies tatsächlich, so dass ein SELECTmit nicht ORDER BYwirklich nicht deterministisch ist, und nicht nur in der Theorie oder weil sich die Daten geändert haben.)
Jeroen Mostert

@JeroenMostert: Undefiniertes Verhalten wird nur noch schlimmer. Was passiert, wenn es nicht in Ordnung ist und das Delta zum Indizieren in ein Array verwendet wurde?
Joshua

2

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- Versionen (die Sie getestet haben) lautet: Nein - für diese bestimmte Abfrage. Sortierreihenfolge ist garantiert.

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

Das Handbuch weist sogar im Kapitel Aggregatfunktionen darauf 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 ORDER BYdem Äußeren einen weiteren hinzu SELECT. (In diesem Fall wäre das innere ORDER BYRauschen für diese einfache Abfrage redundantes Rauschen.)


Stimmt es, wenn "table"es sich nicht um eine einfache Basistabelle, sondern um eine komplexe Ansicht oder eine partitionierte Tabelle handelt? Stimmt es, wenn der Plan auch parallel ausgeführt wird? Gilt das auch für Postgres 10? (Ich frage nur, ich bin mir nicht sicher, ob ich eine dieser Fragen beantworten kann.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ: Ich habe Postgres 10 nicht für all diese getestet, aber ich bin mir ziemlich sicher, dass es auf jeden Fall wahr ist. Die Reihenfolge wird in der äußeren Abfrage für den einfachen Fall angewendet und nicht geändert.
Erwin Brandstetter
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.