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?
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);1row fetched in0.0032(1.2679 seconds)SELECT COUNT(*)FROM t_inner WHERE val =1000OR val =2000OR val =3000OR val =4000OR val =5000OR val =6000OR val =7000OR val =8000OR val =9000;1row fetched in0.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.
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.
CREATETABLE 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')
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.
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)
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.
Réponses:
Je suppose que vous souhaitez connaître la différence de performance entre les éléments suivants:
Selon le manuel de MySQL si les valeurs sont constantes
IN
trie la liste et utilise ensuite une recherche binaire. J'imagine que lesOR
évalue un par un sans ordre particulier. C'est doncIN
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:
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.
la source
IN
méthode rend plus facile à optimiser que tout un tas deOR
clauses éventuellement liées . Je serais surpris s'il existe un moteur où laOR
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 unIN
?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.
Même si la requête utilise
IN
, le plan d'exécution indique qu'il utiliseOR
:la source
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 deuxIN
etOR
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.
la source
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
IN
gagne clairement)la source
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.
la source
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
la source