IN vs OR dans la clause SQL WHERE

150

Lorsque vous traitez avec de grandes bases de données, lesquelles fonctionnent mieux, INou ORdans la Whereclause SQL ?

Y a-t-il une différence dans la manière dont ils sont exécutés?

Félix
la source
Ma première hypothèse serait que OR fonctionne mieux, à moins que le moteur SQL ne convertisse IN en OR derrière la scène. Avez-vous vu le plan de requête de ces deux?
Raj
Double possible de la performance MYSQL OR vs IN
Steve Chambers

Réponses:

170

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 INplus 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.

Mark Byers
la source
20
Si l'optimiseur vaut son sel, ils devraient en faire autant.
Janick Bernet
27
@inflagranti: Aucun optimiseur n'est malheureusement parfait. Les optimiseurs sont des programmes extrêmement complexes et chaque implémentation aura ses propres forces et faiblesses. C'est pourquoi je dis que vous devriez profiler sur une mise en œuvre spécifique. J'imagine que la structure supplémentaire de la INméthode rend plus facile à optimiser que tout un tas de ORclauses éventuellement liées . Je serais surpris s'il existe un moteur où la ORméthode est plus rapide, mais je ne suis pas surpris qu'il y ait des moments où OR soit plus lent.
Mark Byers
2
@MarkByers L'optimiseur ne pourrait-il pas toujours remplacer plusieurs ORs par un IN?
tymtam le
36

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')                                              
Peter Lang
la source
1
Que se passe-t-il dans Oracle si vous testez plus de 3 valeurs? Savez-vous si Oracle est incapable d'effectuer la même optimisation de recherche binaire que MySQL ou l'exécute-t-il dans les deux cas?
Mark Byers
2
@Mark Byers: j'ai essayé la même requête avec 10 valeurs, toujours le même résultat. Notez que l'optimiseur a utilisé mes valeurs par ordre alphabétique. Je ne serais pas surpris si Oracle faisait une optimisation interne de ce filtre ...
Peter Lang
5
Oracle a également une INLIST ITERATORopération, qu'il sélectionnerait s'il y avait un index qu'il pourrait utiliser. Pourtant, quand je l'ai essayé, les deux INet ORse retrouvent avec le même plan d'exécution.
Cheran Shunmugavel
7

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.

Alessandro Rossi
la source
6

Je pense qu'oracle est assez intelligent pour convertir le moins efficace (quel qu'il soit) en l'autre. Je pense donc que la réponse devrait plutôt dépendre de la lisibilité de chacun (là où je pense que cela INgagne clairement)

soulmerge
la source
2

ORa du sens (du point de vue de la lisibilité), quand il y a moins de valeurs à comparer. INest utile esp. lorsque vous disposez d'une source dynamique avec laquelle vous souhaitez comparer les valeurs.

Une autre alternative consiste à utiliser un JOINavec une table temporaire.
Je ne pense pas que les performances devraient être un problème, à condition que vous ayez les index nécessaires.

shahkalpesh
la source
-2

J'ai fait une requête SQL dans un grand nombre de OU (350). Postgres le fait 437,80 ms .

Utilisez OU

Maintenant, utilisez IN:

Utiliser dans

23,18 ms

user3003962
la source
4
Ce n'est pas tout à fait la même chose, puisque vous avez utilisé une sous-requête pour la clause IN.
gliljas