È VERAMENTE possibile che l'ordine non sia garantito per questa particolare tabella derivata ridondante?


12

Mi sono imbattuto in questa domanda in una conversazione su Twitter con Lukas Eder .

Sebbene il comportamento corretto sia applicare la clausola ORDER BY sulla query più esterna, poiché, qui, non stiamo usando DISTINCT, GROUP BY, JOIN o qualsiasi altra clausola WHERE nella query più esterna, perché un RDBMS non dovrebbe semplicemente passare la dati in arrivo come sono stati ordinati dalla query interna?

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

Quando si esegue questo esempio su PostgreSQL, almeno si ottiene lo stesso piano di esecuzione sia per la query interna che per questo esempio di tabella derivata, nonché lo stesso set di risultati.

Quindi, suppongo che il Pianificatore eliminerà semplicemente la query più esterna perché è ridondante o semplicemente passa attraverso i risultati dalla tabella interna.

Qualcuno pensa che questo potrebbe non essere il caso?


4
Si noti che la query non riuscirà in SQL Server perché non è consentito un ordine in una tabella derivata.
a_horse_with_no_name

Perché sei così incredulo? Perché dovresti assumere qualcosa? Quando scrivi un programma che ti lascia una scelta, ti aspetti che gli utenti si aspettino cose dalla tua scelta? Leggi informazioni sull'ottimizzazione / implementazione logica e fisica delle query
Philipxy,

2
"Suppongo che il pianificatore eliminerà semplicemente la query più esterna perché è ridondante o semplicemente passa attraverso i risultati dalla tabella interna." Si potrebbe anche facilmente supporre che il Pianificatore eliminerà la clausola di ordinamento sulla query interna perché non ha senso nel contesto.
Carattere jolly

MariaDB, circa 2012, discute il problema. La mancanza della parte internaORDER BYcomporta una diversa ottimizzazione per max .
Rick James,

1
In realtà, hai ragione per Postgres.
Erwin Brandstetter,

Risposte:


20

La maggior parte dei database è abbastanza chiara sul fatto che ORDER BYin una sottoquery sia:

  • Non consentito: ad esempio SQL Server, Sybase SQL Anywhere (a meno che non sia integrato con TOPo OFFSET .. FETCH)
  • Senza significato: ad esempio PostgreSQL, DB2 (di nuovo, a meno che non sia integrato con OFFSET .. FETCHo LIMIT)

Ecco un esempio dal manuale DB2 LUW (l'enfasi è mia)

Una clausola ORDER BY in una sottoselezione non influisce sull'ordine delle righe restituite da una query. Una clausola ORDER BY ha effetto solo sull'ordine delle righe restituite se è specificata nella fullselect più esterna.

La formulazione è abbastanza esplicita, proprio come PostgreSQL :

Se non viene scelto l'ordinamento, le righe verranno restituite in un ordine non specificato. L'ordine effettivo in quel caso dipenderà dalla scansione e dai tipi di piano di join e dall'ordine su disco, ma non deve essere invocato . Un particolare ordinamento di output può essere garantito solo se la fase di ordinamento viene scelta esplicitamente.

Da questa specifica, si può seguire che qualsiasi ordinamento risultante dalla ORDER BYclausola in una tabella derivata è semplicemente accidentale e potrebbe coincidere casualmente con il tuo ordinamento previsto (cosa che fa nella maggior parte dei database nel tuo banale esempio), ma non sarebbe saggio fare affidamento su Questo.

Nota a margine su DB2:

In particolare, DB2 ha una funzione meno nota chiamataORDER BY ORDER OF <table-designator> , che può essere utilizzata come segue:

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

In questo caso particolare, l'ordinamento della tabella derivata può essere riutilizzato esplicitamente nella parte più esterna di SELECT

Nota a margine su Oracle:

Per anni è stata una pratica in Oracle implementare l' OFFSETimpaginazione utilizzando ROWNUM, che può essere ragionevolmente calcolato solo dopo aver ordinato una tabella derivata:

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

Ci si può ragionevolmente aspettare che, almeno in presenza di ROWNUMuna query, le future versioni di Oracle non interrompano questo comportamento al fine di non interrompere praticamente tutto il precedente SQL Oracle esistente, che non è ancora migrato verso il molto più desiderabile e OFFSET .. FETCHsintassi standard SQL leggibile :

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

Meaningless: E.g. PostgreSQLin realtà dovrebbe essere: 'inaffidabile', perché fa dire qualcosa. Le righe vengono ordinate nella query interna e tale ordine viene mantenuto nei livelli di query esterni a meno che non sia indicato diversamente o il riordino sia opportuno per operazioni aggiuntive. Anche se questo è solo un dettaglio dell'implementazione, non è privo di significato. Questo può essere usato per input ordinati per funzioni aggregate. Il manuale suggerisce persino quanto segue: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter,

La citazione che hai aggiunto per Postgres si applica in realtà a un caso diverso: query senza ORDER BYrisposta.
Erwin Brandstetter,

@ErwinBrandstetter: sentiti libero di aggiungere una risposta con questi dettagli. Personalmente non sono d'accordo sul fatto che i dettagli di implementazione siano significativi. Proprio oggi, ho imparato che ai vecchi tempi, le persone si affidavano a Oracle che eseguiva sempre un gruppo ordinato per operazione in Oracle 8i (credo), quando all'improvviso, una versione più recente introdusse il gruppo con hash, il che ruppe l'ipotesi che alcuni impliciti si può fare affidamento sull'ordinamento. In altre parole: mi piace metterlo in grassetto. Senza senso , piuttosto che oh se conosci i dettagli intricati della versione xyz, puoi davvero ...
Lukas Eder

Ho già aggiunto una risposta. Se abbiamo scelto di ignorare comportamenti non standard o quali altri buoni consigli abbiamo accanto alla domanda: l' ordine è garantito per la query data? È per Postgres. Non è (o nemmeno applicabile) per altri RDBMS. E questo vale per tutte le versioni esistenti di Postgres, non solo per la versione xyz È persino documentato (con riserve). Il tuo preventivo è fuorviante. Se vogliamo ignorare il comportamento non standard, potremmo iniziare con Oracle facendoci credere che NULL e la stringa vuota siano uguali. Anche ortogonale alla domanda.
Erwin Brandstetter,

@ErwinBrandstetter: interessante, grazie per l'aggiornamento. Questa garanzia ti sta riferendo a documentata?
Lukas Eder,

12

Sì. Senza una ORDER BYclausola l'ordine di output non è definito e il pianificatore di query rientra nella sua sfera di competenza supponendo che tu lo sappia e lo capisca.

Può decidere che, poiché la query esterna non specifica un ordine, può eliminare l'ordinamento nella query interna per evitare un'operazione di ordinamento, soprattutto se non esiste alcun indice cluster o nessun indice a supporto dell'ordinamento. Se non lo fa ora si può fare nelle versioni future.

Non fare affidamento su comportamenti indefiniti. Se hai bisogno di un ordine specifico, dai una ORDER BYclausola nel posto appropriato.


Durante il test su PostgreSQL, l'ordinamento è stato eseguito dopo una scansione sequenziale poiché non avevo alcun indice sulla colonna utilizzata da ORDER BY. Quale RDBMS pensi salterà la query interna ORDER BY?
Vlad Mihalcea,

5
Non posso dire di sapere cosa accadrà , solo che tutti sono perfettamente liberi di farlo se lo desiderano - sarebbe un'ottimizzazione perfettamente accettabile secondo gli standard generali e le specifiche del prodotto. SQL Server rifiuterà la query in modo definitivo (a meno che tu non includa TOP 100%la query corrente non è portatile, dovrebbe essere una priorità per il tuo progetto. Poiché Postgres obbedisce all'ordine nella query interna ora non implica che lo farà sempre in futuro (o le versioni precedenti lo fanno, in effetti), quindi dovresti evitare di fare affidamento sul comportamento per ogni evenienza.
David Spillett,

1
@VladMihalcea un DBMS che "ottimizza" il ridondante ORDER BYè MariaDB: Perché ORDER BY in una sottoquery FROM viene ignorato?
ypercubeᵀᴹ

6

È proprio il problema con un comportamento indefinito: funziona per te, funziona per me, riformatta l'HDD in prod;)

Possiamo fare un passo indietro e dire che, in un certo senso, hai ragione: non esiste alcun motivo terreno per cui un RDBMS sano riorganizzerebbe le file nella selezione interna. Ma non è garantito, il che significa che in futuro potrebbe esserci una ragione e i fornitori sono liberi di farlo. Ciò significa che qualsiasi codice che si basa su questo comportamento è in balia di una modifica che un fornitore potrebbe apportare e che non avrebbe l'obbligo di pubblicizzare, poiché non si tratta di una modifica sostanziale rispetto a un POV API.


2
L'unico motivo per cui è possibile ottimizzare l'ordine è la velocità. Restituire le righe in un ordine diverso potrebbe essere più efficiente.
TomTom,

2
In particolare, il server può sfruttare il parallelismo per leggere la tabella. Se lo fa, e non è necessario forzare un ordine, otterrai le righe indietro comunque i thread le leggeranno. (SQL Server in realtà lo fa, in modo che un SELECTcon no sia ORDER BYveramente non deterministico, e non solo in teoria o perché i dati sono cambiati.)
Jeroen Mostert,

@JeroenMostert: il comportamento indefinito peggiora. Cosa succede se è fuori servizio e il delta è stato utilizzato per indicizzare in un array?
Giosuè,

2

È VERAMENTE possibile che l'ordine non sia garantito per questa particolare tabella derivata ridondante?

La risposta per tutte le versioni attualmente esistenti di Postgres (che stavi testando) è: No - per questa particolare query. L'ordinamento è garantito.

Le persone del server SQL non si sentiranno a proprio agio in quanto Microsoft non consente nemmeno ORDER BYnelle subquery. L'ordinamento è garantito per questa semplice query in Postgres. ORDER BYviene applicato nella sottoquery e la query esterna non esegue alcuna operazione che potrebbe modificare l'ordine.

Il manuale suggerisce anche tanto nel capitolo Funzioni aggregate :

In alternativa, in genere funzionerà fornendo i valori di input da una sottoquery ordinata.

Si noti che ciò è vero solo se i livelli di query esterni non aggiungono operazioni che potrebbero modificare l'ordine. Quindi è "garantito" solo per il caso semplice e non è supportato dallo standard SQL. Postgres è libero di riordinare se è opportuno per ulteriori operazioni. In caso di dubbio aggiungine un altro ORDER BYall'esterno SELECT. (Nel qual caso l'interno ORDER BYsarebbe rumore ridondante per questa semplice query.)


È vero quando "table"non è una tabella di base semplice ma una vista complessa o una tabella partizionata? È vero anche quando il piano ha un'esecuzione parallela? È vero anche in Postgres 10? (Sto solo chiedendo, non sono sicuro della risposta a nessuna di queste domande.)
ypercubeᵀᴹ

@ ypercubeᵀᴹ: non ho testato Postgres 10 per tutti questi, ma sono abbastanza sicuro che sia vero in ogni caso. L'ordine viene applicato e non modificato nella query esterna per il caso semplice.
Erwin Brandstetter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.