web-dev-qa-db-fra.com

IN vs OR dans la clause SQL WHERE

Lorsqu'il s'agit de bases de données volumineuses, laquelle donne de meilleurs résultats, IN ou OR dans la clause SQL Where-?

Y a-t-il une différence dans la façon dont ils sont exécutés?

141
felix

Je suppose que vous voulez connaître la différence de performances entre les éléments suivants:

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

Selon le manuel pour MySQL si les valeurs sont constantes, IN trie la liste puis utilise une recherche binaire. J'imagine que OR les évalue un par un sans ordre particulier. Donc, IN est plus rapide dans certaines circonstances.

La meilleure façon de le 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 perceptible dans les performances - les deux sont presque instantanées. Lorsque la colonne n'est pas indexée, j'ai 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)

Ainsi, dans ce cas, la méthode utilisant OR est environ 30% plus lente. L'ajout de termes supplémentaires accentue la différence. Les résultats peuvent varier sur d'autres bases de données et sur d'autres données.

152
Mark Byers

La meilleure façon de le savoir est de regarder 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 dit 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')                                              
32
Peter Lang

L'opérateur OR nécessite un processus d'évaluation beaucoup plus complexe que la construction IN, car il autorise de nombreuses conditions, et pas seulement la même chose que IN.

Voici un exemple de ce que vous pouvez utiliser avec OR mais qui ne sont pas compatibles avec IN: supérieur. Supérieur ou supérieur, inférieur, inférieur ou égal, LIKE et d’autres comme Oracle REGEXP_LIKE. In En outre, considérez que les conditions peuvent ne pas toujours comparer la même valeur.

Pour l’optimiseur de requêtes, il est plus facile de gérer l’opérateur IN car c’est seulement 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 opérateur, l'optimiseur peut ne pas considérer que vous utilisez toujours l'opérateur = sur la même valeur et, s'il ne réalise pas une élaboration plus profonde et beaucoup plus complexe, il pourrait probablement exclure qu'il puisse en exister only = opérateurs pour les mêmes valeurs sur toutes les conditions impliquées, avec pour conséquence une interdiction des méthodes de recherche optimisées telles que 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 pourrait arriver (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.

6
Alessandro Rossi

Je pense qu'Oracle est assez intelligent pour convertir le moins efficace (quel qu'il soit) en un autre. Donc, je pense que la réponse devrait plutôt dépendre de la lisibilité de chacun (où je pense que IN gagne clairement)

6
soulmerge

OR est logique (du point de vue de la lisibilité), quand il y a moins de valeurs à comparer. IN est utile esp. lorsque vous avez 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 la performance devrait être un problème, à condition que vous ayez les index nécessaires.

2
shahkalpesh

J'ai fait une requête SQL dans un grand nombre de OR (350). Postgres le fait 437.80ms.

Use OR

Maintenant, utilisez IN:

Use IN

23.18ms

1
user3003962