Quando si ha a che fare con database di grandi dimensioni, che offre prestazioni migliori IN
o OR
nella Where
clausola SQL ?
C'è qualche differenza nel modo in cui vengono eseguiti?
Quando si ha a che fare con database di grandi dimensioni, che offre prestazioni migliori IN
o OR
nella Where
clausola SQL ?
C'è qualche differenza nel modo in cui vengono eseguiti?
Risposte:
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 IN
ordina l'elenco e quindi utilizza una ricerca binaria. Immagino che OR
li 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.
IN
metodo renda più facile l'ottimizzazione di un intero gruppo di OR
clausole possibilmente correlate . Sarei sorpreso se c'è un motore in cui il OR
metodo è più veloce, ma non mi sorprende che ci siano momenti in cui OR è più lento.
OR
s con un IN
?
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')
INLIST ITERATOR
un'operazione, che selezionerebbe se ci fosse un indice che potrebbe usare. Tuttavia, quando l'ho provato, entrambi IN
e OR
finiscono con lo stesso piano di esecuzione.
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.
OR
ha 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 JOIN
con una tabella temporanea.
Non credo che le prestazioni dovrebbero essere un problema, a condizione che tu abbia gli indici necessari.
Ho fatto una query SQL in un gran numero di OR (350). Postgres lo fa 437.80ms .
Ora usa IN:
23.18ms