L'ordine delle clausole dove è importante in SQL?


121

Diciamo che ho una tabella chiamata PEOPLEcon 3 colonne ID, LastName, FirstName, nessuna di queste colonne è indicizzata.
LastNameè più unico ed FirstNameè meno unico.

Se eseguo 2 ricerche:

select * from PEOPLE where FirstName="F" and LastName="L" 
select * from PEOPLE where LastName="L" and FirstName="F"

La mia convinzione è che il secondo sia più veloce perché il criterio più unico ( LastName) viene prima nella whereclausola e i record verranno eliminati in modo più efficiente. Non penso che l'ottimizzatore sia abbastanza intelligente da ottimizzare il primo sql.

La mia comprensione è corretta?


8
No, quell'ordine non ha importanza: qualsiasi ottimizzatore di query decente esaminerà tutte le clausole WHERE e troverà il modo più efficiente per soddisfare quella query
marc_s

3
Quali sono state le tue osservazioni quando hai eseguito queste due dichiarazioni? Come erano i piani di esecuzione?
Conrad Frix

3
Ti riferisci a un RDBMS specifico? Ci sono davvero delle differenze.
Bjoern


Risposte:


101

No, quell'ordine non ha importanza (o almeno: non dovrebbe importare).

Qualsiasi ottimizzatore di query decente esaminerà tutte le parti della WHEREclausola e troverà il modo più efficiente per soddisfare quella query.

So che l'ottimizzatore di query di SQL Server sceglierà un indice adatto, indipendentemente dall'ordine in cui si trovano le due condizioni. Presumo che altri RDBMS avranno strategie simili.

Ciò che importa è se hai o meno un indice adatto per questo!

Nel caso di SQL Server, probabilmente utilizzerà un indice se hai:

  • un indice su (LastName, FirstName)
  • un indice su (FirstName, LastName)
  • un indice su solo (LastName), o solo (FirstName)(o entrambi)

D'altra parte, sempre per SQL Server, se usi SELECT *per prendere tutte le colonne da una tabella e la tabella è piuttosto piccola, allora ci sono buone probabilità che Query Optimizer esegua semplicemente una scansione della tabella (o dell'indice cluster) invece di usare un indice (perché la ricerca nella pagina di dati completa per ottenere tutte le altre colonne diventa troppo costosa molto rapidamente).


Se non ci sono indici, l'operazione potrebbe essere corretta, a seconda dei dati. Ovviamente fare qualcosa di simile senza indici, sarebbe una decisione strana ...
Tony Hopkinson

@TonyHopkinson: Non la penso così - anche senza indici dubito che ci sia alcuna differenza. Dopo tutto: senza gli indici, cos'altro può fare l'RDBMS se non una scansione completa della tabella, davvero ??
marc_s


3
Una cosa strana è che per la prima esecuzione di una query l'ordine delle condizioni in una clausola WHERE DOES MATTER! Avevo due condizioni, qualcosa del tipo: WHERE T1.col_1/T2.col_2 > 10 AND T2.col_2 <> 0e ho ricevuto un DIVIDE BY 0errore. Dopo aver cambiato l'ordine le condizioni la query è stata eseguita con successo. Quindi ho ripristinato l'ordine in modo che mi aspettassi di ricevere nuovamente l'errore, ma questa volta ha funzionato! Alla fine la mia conclusione è stata che per la prima esecuzione l'ordine è importante, fino a quando non viene costruito il piano di esecuzione. non importa perché l'ottimizzatore / piano esecutivo se ne occuperà
Radu Gheorghiu

1
Mi piace che tu abbia detto "... o almeno: non dovrebbe importare" - Sono totalmente d'accordo. A volte ha importanza, purtroppo. Ho visto casi in cui SQL era troppo complesso per essere gestito dall'ottimizzatore e cose come l'ordine delle colonne e l'ordine dei join di tabella hanno fatto la differenza. Dipende dall'RDBMS, dalla complessità dell'istruzione SQL e persino dal rilascio. SQL molto complesso può portare a decisioni errate dell'ottimizzatore o all'utilizzo di impostazioni predefinite hardcoded nel codice dell'ottimizzatore.
Victor Di Leo

19

L'ordine delle clausole WHERE non dovrebbe fare la differenza in un database conforme allo standard SQL. L'ordine di valutazione non è garantito nella maggior parte dei database.

Non pensare che SQL si preoccupi dell'ordine. Quanto segue genera un errore in SQL Server:

select *
from INFORMATION_SCHEMA.TABLES
where ISNUMERIC(table_name) = 1 and CAST(table_name as int) <> 0

Se la prima parte di questa clausola fosse eseguita per prima, solo i nomi delle tabelle numeriche verrebbero espressi come numeri interi. Tuttavia, non riesce, fornendo un chiaro esempio che SQL Server (come con altri database) non si preoccupa dell'ordine delle clausole nell'istruzione WHERE.


Che cosa ha a che fare la query che causa un errore con l'ordine di valutazione del predicato WHERE?
Jim

7
@Jim Se ISNUMERIC(table_name) = 1fosse stato valutato per primo, CASTverrebbe chiamato solo per i nomi delle tabelle numeriche. Ma poiché non CASTviene valutato per primo, viene valutato anche per i nomi di tabella non numerici, causando il messaggio di errore.
hibbelig

2
Ottima chiarificazione
neeohw

Giusto per essere sicuro di aver verificato se lo scambio delle condizioni avrebbe indotto il server SQL a gestirle al contrario, ma fallisce in entrambi i modi. Penso che questo possa significare una delle due cose: (1) non si sta ottimizzando come potrebbe o (2) è un errore in fase di compilazione e SQL non inizia nemmeno a provare a confrontare nulla, salvando preliminarmente. La mia ipotesi è che sia il nr. 2.
Louis Somers

9

ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Ordine di valutazione delle regole

...

Dove la precedenza non è determinata dai formati o dalle parentesi, la valutazione efficace delle espressioni viene generalmente eseguita da sinistra a destra. Tuttavia, dipende dall'implementazione se le espressioni vengono effettivamente valutate da sinistra a destra, in particolare quando gli operandi o gli operatori potrebbero causare l'innalzamento delle condizioni o se i risultati delle espressioni possono essere determinati senza valutare completamente tutte le parti dell'espressione.

copiato da qui


2

No, tutti gli RDBM iniziano innanzitutto analizzando la query e ottimizzandola riordinando la clausola where.

A seconda di quale RDBM stai utilizzando puoi visualizzare qual è il risultato dell'analisi (cerca ad esempio il piano di spiegazione in Oracle)

M.


Lo fa in base agli indici. Quindi è indiretto in termini di contenuto.
Tony Hopkinson

1

Dichiarazione OP originale

La mia convinzione è che il secondo sia più veloce perché il criterio più unico (LastName) viene per primo> nella clausola where e i record verranno eliminati in modo più efficiente. Non credo che l'ottimizzatore sia> abbastanza intelligente da ottimizzare il primo sql.

Immagino che tu stia confondendo questo con la selezione dell'ordine delle colonne durante la creazione degli indici in cui devi mettere le colonne più selettive prima delle seconde più selettive e così via.

A proposito, per le due query precedenti, l'ottimizzatore del server SQL non eseguirà alcuna ottimizzazione ma utilizzerà il piano Trivila purché il costo totale del piano sia inferiore al costo soglia del parallelismo.


0

È vero fin dove arriva, supponendo che i nomi non siano indicizzati. Dati diversi lo farebbero però sbagliato. Per scoprire in che modo farlo, che potrebbe differire ogni volta, il DBMS dovrebbe eseguire una query di conteggio distinta per ogni colonna e confrontare i numeri, il che costerebbe più della semplice scrollata di spalle e andare avanti con esso.

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.