Lorsque vous traitez avec de grandes bases de données, lesquelles fonctionnent mieux, IN
ou OR
dans la Where
clause SQL ?
Y a-t-il une différence dans la manière dont ils sont exécutés?
Lorsque vous traitez avec de grandes bases de données, lesquelles fonctionnent mieux, IN
ou OR
dans la Where
clause SQL ?
Y a-t-il une différence dans la manière dont ils sont exécutés?
Réponses:
Je suppose que vous souhaitez connaître la différence de performance entre les éléments suivants:
WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'
Selon le manuel de MySQL si les valeurs sont constantesIN
trie la liste et utilise ensuite une recherche binaire. J'imagine que les OR
évalue un par un sans ordre particulier. C'est donc IN
plus rapide dans certaines circonstances.
La meilleure façon de savoir est de profiler les deux sur votre base de données avec vos données spécifiques pour voir laquelle est la plus rapide.
J'ai essayé les deux sur un MySQL avec 1000000 lignes. Lorsque la colonne est indexée, il n'y a pas de différence de performances perceptible - les deux sont presque instantanées. Lorsque la colonne n'est pas indexée, j'ai obtenu ces résultats:
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)
Donc, dans ce cas, la méthode utilisant OR est environ 30% plus lente. L'ajout de termes augmente la différence. Les résultats peuvent varier sur d'autres bases de données et sur d'autres données.
IN
méthode rend plus facile à optimiser que tout un tas de OR
clauses éventuellement liées . Je serais surpris s'il existe un moteur où la OR
méthode est plus rapide, mais je ne suis pas surpris qu'il y ait des moments où OR soit plus lent.
OR
s par un IN
?
La meilleure façon de le savoir est d'examiner le plan d'exécution.
Je l'ai essayé avec Oracle , et c'était exactement la même chose.
CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );
SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );
Même si la requête utilise IN
, le plan d'exécution indique qu'il utilise 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
opération, qu'il sélectionnerait s'il y avait un index qu'il pourrait utiliser. Pourtant, quand je l'ai essayé, les deux IN
et OR
se retrouvent avec le même plan d'exécution.
L'opérateur OR a besoin d'un processus d'évaluation beaucoup plus complexe que la construction IN car il autorise de nombreuses conditions, pas seulement égales comme IN.
Voici un aperçu de ce que vous pouvez utiliser avec OR mais qui n'est pas compatible avec IN: supérieur. supérieur ou égal, inférieur, inférieur ou égal, LIKE et certains plus comme l'oracle REGEXP_LIKE. En outre, considérez que les conditions peuvent ne pas toujours comparer la même valeur.
Pour l'optimiseur de requête, il est plus facile de gérer l'opérateur IN car il s'agit uniquement d'une construction qui définit l'opérateur OR sur plusieurs conditions avec l'opérateur = sur la même valeur. Si vous utilisez l'opérateur OR, l'optimiseur peut ne pas considérer que vous utilisez toujours l'opérateur = sur la même valeur et, s'il n'effectue pas une élaboration plus profonde et beaucoup plus complexe, il pourrait probablement exclure qu'il n'y ait que = opérateurs pour les mêmes valeurs sur toutes les conditions impliquées, avec une interdiction conséquente de méthodes de recherche optimisées comme la recherche binaire déjà mentionnée.
[EDIT] Il est probable qu'un optimiseur n'implémente pas le processus d'évaluation IN optimisé, mais cela n'exclut pas qu'une seule fois cela puisse se produire (avec une mise à niveau de la version de la base de données). Donc, si vous utilisez l'opérateur OR, cette élaboration optimisée ne sera pas utilisée dans votre cas.
OR
a du sens (du point de vue de la lisibilité), quand il y a moins de valeurs à comparer.
IN
est utile esp. lorsque vous disposez d'une source dynamique avec laquelle vous souhaitez comparer les valeurs.
Une autre alternative consiste à utiliser un JOIN
avec une table temporaire.
Je ne pense pas que les performances devraient être un problème, à condition que vous ayez les index nécessaires.
J'ai fait une requête SQL dans un grand nombre de OU (350). Postgres le fait 437,80 ms .
Maintenant, utilisez IN:
23,18 ms