Czy NAPRAWDĘ jest możliwe, że zamówienie nie będzie gwarantowane dla tej konkretnej zbędnej tabeli pochodnej?

12

Natknąłem się na to pytanie w rozmowie na Twitterze z Lukasem Ederem .

Chociaż poprawnym działaniem byłoby zastosowanie klauzuli ORDER BY w najbardziej zewnętrznym zapytaniu, ponieważ tutaj nie używamy DISTINCT, GROUP BY, JOIN ani żadnej innej klauzuli WHERE w najbardziej zewnętrznym zapytaniu, dlaczego RDBMS po prostu nie przekaże przychodzące dane, które zostały posortowane według wewnętrznego zapytania?

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

Uruchamiając ten przykład na PostgreSQL, otrzymujesz co najmniej ten sam plan wykonania zarówno dla wewnętrznego zapytania, jak i tego przykładu tabeli pochodnej, a także ten sam zestaw wyników.

Zakładam więc, że Planista po prostu odrzuci najbardziej zewnętrzne zapytanie, ponieważ jest ono zbędne lub po prostu przechodzi przez wyniki z wewnętrznej tabeli.

Czy ktoś uważa, że ​​tak nie jest?

Vlad Mihalcea
źródło
4
Pamiętaj, że zapytanie zakończy się niepowodzeniem w programie SQL Server, ponieważ kolejność według nie jest dozwolona w tabeli pochodnej.
a_horse_w_no_name
Dlaczego jesteś taki niewiarygodny? Dlaczego miałbyś cokolwiek zakładać? Kiedy piszesz program, który pozostawia Ci wybór, czy oczekujesz, że użytkownicy będą oczekiwać od ciebie wyboru? Przeczytaj o logicznej i fizycznej optymalizacji / implementacji zapytań.
philipxy
2
„Zakładam, że Planista po prostu odrzuci najbardziej zewnętrzne zapytanie, ponieważ jest zbędne lub po prostu przejdzie wyniki z wewnętrznej tabeli”. Równie łatwo można założyć, że Planista odrzuci klauzulę porządkowania w wewnętrznym zapytaniu, ponieważ nie ma ona znaczenia w kontekście.
Wildcard
MariaDB, około 2012 roku, omawia ten problem. Brak wewnętrznejORDER BYprowadzi do innej optymalizacji dla grupowego maks .
Rick James
1
Właściwie masz rację dla Postgres.
Erwin Brandstetter,

Odpowiedzi:

20

Większość baz danych jest dość jasna na temat faktu, że ORDER BYw podzapytaniu jest albo:

  • Niedozwolone: ​​np. SQL Server, Sybase SQL Anywhere (chyba że uzupełnione o TOPlub OFFSET .. FETCH)
  • Bez znaczenia: np. PostgreSQL, DB2 (ponownie, chyba że uzupełnione o OFFSET .. FETCHlub LIMIT)

Oto przykład z podręcznika DB2 LUW (wyróżnienie moje)

Klauzula ORDER BY w podselekcji nie wpływa na kolejność wierszy zwracanych przez zapytanie. Klauzula ORDER BY wpływa tylko na kolejność zwracanych wierszy, jeśli jest określona w skrajnie pełnym wyborze.

Sformułowanie jest dość wyraźne, podobnie jak PostgreSQL :

Jeśli sortowanie nie zostanie wybrane, wiersze zostaną zwrócone w nieokreślonej kolejności. Rzeczywista kolejność w takim przypadku będzie zależeć od typu skanowania i planu dołączania oraz kolejności na dysku, ale nie można na nim polegać . Szczególne uporządkowanie wyjściowe może być zagwarantowane tylko wtedy, gdy zostanie wyraźnie wybrany krok sortowania.

Z tej specyfikacji można ORDER BYwywnioskować, że każde uporządkowanie wynikające z klauzuli w tabeli pochodnej jest jedynie przypadkowe i może przypadkowo pasować do oczekiwanej kolejności (co robi w większości baz danych w trywialnym przykładzie), ale nierozsądne byłoby polegać na to.

Uwaga dodatkowa na temat DB2:

W szczególności DB2 ma mniej znaną funkcję o nazwieORDER BY ORDER OF <table-designator> , której można użyć w następujący sposób:

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

W tym konkretnym przypadku kolejność tabeli pochodnej może zostać ponownie wyraźnie użyta w najbardziej zewnętrznym SELECT

Uwaga dodatkowa na temat Oracle:

Od lat praktyką w Oracle jest stosowanie OFFSETpaginacji przy użyciu ROWNUM, którą można racjonalnie obliczyć dopiero po zamówieniu tabeli pochodnej:

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

Można zasadnie oczekiwać, że przynajmniej w obecności ROWNUMzapytania przyszłe wersje Oracle nie złamią tego zachowania, aby nie złamać prawie całej dotychczasowej wersji Oracle SQL, która nie została jeszcze przeniesiona do znacznie bardziej pożądanej i czytelna standardowa OFFSET .. FETCHskładnia SQL :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
Lukas Eder
źródło
Meaningless: E.g. PostgreSQLpowinien być naprawdę: „niewiarygodne”, ponieważ ma coś znaczyć. Wiersze są sortowane w wewnętrznym zapytaniu, a ta kolejność jest utrzymywana na zewnętrznym poziomie zapytania, chyba że zalecono inaczej lub zmiana kolejności jest odpowiednia dla dodatkowych operacji. Nawet jeśli jest to tylko szczegół implementacji, nie jest to bez znaczenia. Można tego użyć do posortowanego wejścia do agregacji funkcji. Podręcznik nawet wskazuje tyle samo: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter,
Cytat dodany do Postgresa dotyczy w rzeczywistości innego przypadku: zapytań ORDER BYw ogóle nie.
Erwin Brandstetter,
@ErwinBrandstetter: Możesz dodać odpowiedź z tymi szczegółami. Osobiście nie zgadzam się, że szczegóły implementacji są znaczące. Właśnie dzisiaj dowiedziałem się, że w dawnych czasach ludzie polegali na Oracle zawsze wykonując posortowaną grupę według operacji w Oracle 8i (wydaje mi się), kiedy nagle nowa wersja wprowadziła grupę haszującą, co złamało założenie, że niektórzy domyślnie można polegać na zamówieniu. Innymi słowy: lubię to odważnie. Bez znaczenia , zamiast och, jeśli znasz skomplikowane szczegóły wersji xyz, możesz faktycznie ...
Lukas Eder
Już dodałem odpowiedź. Niezależnie od tego, czy zdecydowaliśmy się zignorować niestandardowe zachowanie, czy też inna dobra rada, którą mamy, pozostaje poza pytaniem: czy zamówienie jest gwarantowane dla danego zapytania? To jest dla Postgres. To nie jest (lub nawet nie dotyczy) dla innych RDBMS. Dotyczy to wszystkich istniejących wersji Postgres, nie tylko wersji xyz. Jest nawet udokumentowane (z zastrzeżeniami). Twój cytat wprowadza w błąd. Jeśli chcemy zignorować niestandardowe zachowanie, możemy zacząć od Oracle, co pozwoli nam wierzyć, że NULL i pusty ciąg znaków są takie same. Również ortogonalne do pytania.
Erwin Brandstetter,
@ErwinBrandstetter: Ciekawe, dziękuję za aktualizację. Czy to gwarancja, że ​​masz na myśli udokumentowane?
Lukas Eder,
12

Tak. Bez ORDER BYklauzuli kolejność wyjściowa jest niezdefiniowana, a planista zapytań mieści się w zakresie jego kompetencji, aby założyć, że znasz to i rozumiesz.

Może zdecydować, że ponieważ zapytanie zewnętrzne nie określa kolejności, może porzucić porządek w zapytaniu wewnętrznym, aby uniknąć operacji sortowania, szczególnie jeśli nie ma indeksu klastrowego lub w ogóle indeksu do obsługi porządkowania. Jeśli nie teraz , może to zrobić w przyszłych wersjach.

Nigdy nie polegaj na nieokreślonym zachowaniu. Jeśli potrzebujesz konkretnego zamówienia, podaj ORDER BYklauzulę w odpowiednim miejscu.

David Spillett
źródło
Podczas testowania na PostgreSQL sortowanie zostało przeprowadzone po skanie sekwencyjnym, ponieważ nie miałem żadnego indeksu w kolumnie używanej przez ORDER BY. Jak myślisz, który RDBMS pominie wewnętrzne zapytanie ORDER BY?
Vlad Mihalcea
5
Nie mogę powiedzieć, że wiem, co będzie , tylko że wszyscy i tak mają na to pełną swobodę, jeśli sobie tego życzą - byłaby to całkowicie akceptowalna optymalizacja zgodnie z ogólnymi standardami i specyfikacjami produktu. SQL Server całkowicie odrzuci zapytanie (chyba że zostanie to uwzględnione, TOP 100%więc bieżące zapytanie nie jest przenośne, powinno to być priorytetem dla twojego projektu. Ponieważ Postgres przestrzega kolejności w wewnętrznym zapytaniu, nie oznacza to, że zawsze będzie to robić w przyszłości (lub w rzeczywistości starsze wersje), więc na wszelki wypadek powinieneś unikać polegania na zachowaniu
David Spillett
1
@VladMihalcea DBMS, który „optymalizuje” nadmiar, ORDER BYto MariaDB: Dlaczego ORDER BY w podzapytaniu FROM jest ignorowany?
ypercubeᵀᴹ
6

To właśnie problem z nieokreślonym zachowaniem - działa dla ciebie, działa dla mnie, formatuje HDD w prod;)

Możemy cofnąć się o krok i powiedzieć, że w pewnym sensie masz rację - nie ma ziemskiego powodu, dla którego rozsądny system RDBMS zmieniłby rzędy w wewnętrznej selekcji. Ale nie jest to gwarantowane - co oznacza, że ​​w przyszłości może być jakiś powód, a sprzedawcy mogą to zrobić. Oznacza to, że każdy kod, który opiera się na tym zachowaniu, jest zdany na zmianę, którą może wprowadzić sprzedawca, którego nie byłby zobowiązany do opublikowania, ponieważ nie jest to przełomowa zmiana w stosunku do POV API.

PaulJWilliams
źródło
2
Jednym z powodów, dla których może zoptymalizować zamówienie, jest szybkość. Zwracanie wierszy w innej kolejności może być bardziej wydajne.
TomTom,
2
W szczególności serwer może wykorzystać równoległość do odczytu tabeli. Jeśli tak się stanie i nie będzie trzeba egzekwować zamówienia, odzyskasz wiersze, ale wątki je odczytują. (SQL Server faktycznie to robi, więc tak naprawdę SELECTnie ORDER BYjest niedeterministyczny i nie tylko teoretycznie, albo dlatego, że dane się zmieniły)
Jeroen Mostert
@JeroenMostert: Niezdefiniowane zachowanie tylko się pogarsza. Co się stanie, jeśli nie działa, a delta została użyta do zaindeksowania tablicy?
Joshua
2

Czy NAPRAWDĘ jest możliwe, że zamówienie nie będzie gwarantowane dla tej konkretnej zbędnej tabeli pochodnej?

Odpowiedź dla wszystkich obecnie istniejących wersji Postgres (które testowałeś) brzmi: Nie - dla tego konkretnego zapytania. Kolejność sortowania jest gwarantowana.

Ludzie korzystający z serwera SQL nie będą się z tym czuć komfortowo, ponieważ Microsoft nawet nie zezwala ORDER BYna podzapytania. Mimo to kolejność sortowania jest gwarantowana w przypadku tego prostego zapytania w Postgres. ORDER BYjest stosowane w podzapytaniu, a zapytanie zewnętrzne nie robi niczego, co mogłoby zmienić kolejność.

Podręcznik nawet wskazuje tyle samo w rozdziale Funkcje agregujące :

Alternatywnie, podanie wartości wejściowych z posortowanego podzapytania zwykle będzie działać.

Zauważ, że jest to prawdą tylko wtedy, gdy zewnętrzne poziomy zapytań nie dodają operacji, które mogłyby zmienić kolejność. Jest to więc „gwarantowane” tylko w prostym przypadku i nie jest ono wspierane przez standard SQL. Postgres może bezpłatnie zmieniać kolejność, jeśli jest to odpowiednie do dodatkowych operacji. W razie wątpliwości dodaj kolejną ORDER BYdo zewnętrznej SELECT. (W takim przypadku wewnętrzny ORDER BYdźwięk byłby nadmiarowy dla tego prostego zapytania).

Erwin Brandstetter
źródło
Czy to prawda, gdy "table"nie jest to prosta tabela bazowa, ale złożony widok lub tabela podzielona na partycje? Czy to prawda, że ​​plan ma również wykonanie równoległe? Czy to prawda również w Postgres 10? (Pytam tylko, nie jestem pewien na odpowiedź na którekolwiek z tych pytań.)
ypercubeᵀᴹ 13.09.17
@ ypercubeᵀᴹ: Nie testowałem dla nich wszystkich Postgres 10, ale jestem pewien, że tak czy inaczej. Kolejność jest stosowana i nie jest zmieniana w zewnętrznym zapytaniu dla prostej sprawy.
Erwin Brandstetter,