IN vs OR nella clausola WHERE di SQL


150

Quando si ha a che fare con database di grandi dimensioni, che offre prestazioni migliori INo ORnella Whereclausola SQL ?

C'è qualche differenza nel modo in cui vengono eseguiti?


La mia prima ipotesi sarebbe che OR funzioni meglio, a meno che il motore SQL non converta IN in OR dietro la scena. Hai visto il piano di query di questi due?
Raj

Possibile duplicato delle prestazioni MYSQL OR vs IN
Steve Chambers

Risposte:


170

Presumo che tu voglia conoscere la differenza di prestazione tra i seguenti:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

Secondo il manuale di MySQL se i valori sono costanti INordina l'elenco e quindi utilizza una ricerca binaria. Immagino che ORli valuti uno per uno in nessun ordine particolare. Quindi INè più veloce in alcune circostanze.

Il modo migliore per sapere è profilare entrambi sul tuo database con i tuoi dati specifici per vedere quale è più veloce.

Ho provato entrambi su un MySQL con 1000000 righe. Quando la colonna viene indicizzata, non vi è alcuna differenza evidente nelle prestazioni, entrambe sono quasi istantanee. Quando la colonna non è indicizzata ho ottenuto questi risultati:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Quindi in questo caso il metodo che utilizza OR è più lento di circa il 30%. L'aggiunta di più termini aumenta la differenza. I risultati possono variare su altri database e su altri dati.


20
Se l'ottimizzatore vale il suo sale, dovrebbero fare lo stesso.
Janick Bernet,

27
@inflagranti: Purtroppo nessun ottimizzatore è perfetto. Gli ottimizzatori sono programmi estremamente complessi e ogni implementazione avrà i suoi punti di forza e di debolezza. Ecco perché dico che dovresti profilare su un'implementazione specifica. Immagino che la struttura extra del INmetodo renda più facile l'ottimizzazione di un intero gruppo di ORclausole possibilmente correlate . Sarei sorpreso se c'è un motore in cui il ORmetodo è più veloce, ma non mi sorprende che ci siano momenti in cui OR è più lento.
Mark Byers,

2
@MarkByers L'ottimizzatore non potrebbe sempre sostituire più ORs con un IN?
tymtam,

36

Il modo migliore per scoprirlo è guardare il piano di esecuzione.


L'ho provato con Oracle , ed è stato esattamente lo stesso.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Anche se la query utilizza IN, il piano di esecuzione afferma che utilizza OR:

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):                                       
---------------------------------------------------                                       

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              

1
Cosa succede in Oracle se hai più di 3 valori che stai testando? Sai se Oracle non è in grado di eseguire la stessa ottimizzazione della ricerca binaria di MySQL o la esegue in entrambi i casi?
Mark Byers,

2
@Mark Byers: ho provato la stessa query con 10 valori, sempre con lo stesso risultato. Nota che l'ottimizzatore ha fatto ricorso ai miei valori in ordine alfabetico. Non sarei sorpreso se Oracle avesse fatto qualche ottimizzazione interna di quel filtro ...
Peter Lang,

5
Oracle ha anche INLIST ITERATORun'operazione, che selezionerebbe se ci fosse un indice che potrebbe usare. Tuttavia, quando l'ho provato, entrambi INe ORfiniscono con lo stesso piano di esecuzione.
Cheran Shunmugavel,

7

L'operatore OR ha bisogno di un processo di valutazione molto più complesso rispetto al costrutto IN perché consente molte condizioni, non solo uguale a IN.

Ecco un esempio di ciò che è possibile utilizzare con OR ma che non sono compatibili con IN: maggiore. maggiore o uguale, minore, minore o uguale, COME e alcuni più come l'oracolo REGEXP_LIKE. Inoltre, considerare che le condizioni potrebbero non confrontare sempre lo stesso valore.

Per Query Optimizer è più semplice gestire l'operatore IN perché è solo un costrutto che definisce l'operatore OR su più condizioni con = operatore sullo stesso valore. Se si utilizza l'operatore OR, l'ottimizzatore potrebbe non considerare che si sta sempre utilizzando l'operatore = sullo stesso valore e, se non esegue un'elaborazione più approfondita e molto più complessa, probabilmente si potrebbe escludere che potrebbe esserci solo = operatori per gli stessi valori su tutte le condizioni coinvolte, con una conseguente preclusione di metodi di ricerca ottimizzati come la già citata ricerca binaria.

[EDIT] Probabilmente un ottimizzatore potrebbe non implementare un processo di valutazione IN ottimizzato, ma ciò non esclude che una volta ciò possa accadere (con un aggiornamento della versione del database). Pertanto, se si utilizza l'operatore OR, l'elaborazione ottimizzata non verrà utilizzata nel proprio caso.


6

Penso che l'oracolo sia abbastanza intelligente da convertire quello meno efficiente (qualunque sia) nell'altro. Quindi penso che la risposta dovrebbe piuttosto dipendere dalla leggibilità di ciascuno (dove penso che INvince chiaramente)


2

ORha senso (dal punto di vista della leggibilità), quando ci sono meno valori da confrontare. INè utile esp. quando si dispone di una sorgente dinamica, con cui si desidera confrontare i valori.

Un'altra alternativa è utilizzare a JOINcon una tabella temporanea.
Non credo che le prestazioni dovrebbero essere un problema, a condizione che tu abbia gli indici necessari.


-2

Ho fatto una query SQL in un gran numero di OR (350). Postgres lo fa 437.80ms .

Usa OR

Ora usa IN:

Utilizzare in

23.18ms


4
Non è esattamente la stessa cosa, dal momento che hai usato una sottoquery per la clausola IN.
gliljas,
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.