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?
quelle
ORDER BY
führt zu einer unterschiedlichen Optimierung für gruppenweise max .Antworten:
Die meisten Datenbanken sind sich ziemlich klar darüber, dass eine
ORDER BY
in einer Unterabfrage entweder:TOP
oder ergänztOFFSET .. FETCH
)OFFSET .. FETCH
oder ergänztLIMIT
)Hier ist ein Beispiel aus dem DB2 LUW-Handbuch (Schwerpunkt Mine)
Der Wortlaut ist ziemlich explizit, genau wie bei PostgreSQL :
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 wäre unklug, sich darauf zu verlassen Dies.Randnotiz zu DB2:
Insbesondere hat DB2 eine weniger bekannte Funktion namens
ORDER BY ORDER OF <table-designator>
, die wie folgt verwendet werden kann: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
OFFSET
Paginierung mithilfe von zu implementierenROWNUM
, die nur nach Bestellung einer abgeleiteten Tabelle angemessen berechnet werden kann :Es ist zu erwarten, dass
ROWNUM
zukü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-StandardsyntaxOFFSET .. FETCH
:quelle
Meaningless: E.g. PostgreSQL
sollte 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.
ORDER BY
.Ja. Ohne eine
ORDER BY
Klausel 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 BY
der entsprechenden Stelle eine Klausel an.quelle
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.ORDER BY
ist MariaDB: Warum wird ORDER BY in einer FROM-Unterabfrage ignoriert?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.
quelle
SELECT
mit nichtORDER BY
wirklich nicht deterministisch ist, und nicht nur in der Theorie oder weil sich die Daten geändert haben.)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 BY
Benutzer 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 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 im Kapitel Aggregatfunktionen darauf hin :
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 BY
dem Äußeren einen weiteren hinzuSELECT
. (In diesem Fall wäre das innereORDER BY
Rauschen für diese einfache Abfrage redundantes Rauschen.)quelle
"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.)