SQL WHERE子句中的IN vs OR

fel*_*lix 146 sql database

在处理性能更好的大型数据库时,IN还是OR在SQL Where-clause中?

他们的执行方式有什么不同吗?

Mar*_*ers 160

我假设你想知道以下之间的性能差异:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'
Run Code Online (Sandbox Code Playgroud)

根据MySQL手册,如果值是常量IN,则对列表进行排序,然后使用二进制搜索.我想象一下,OR按照一个接一个的顺序对它们进行评估.所以IN在某些情况下更快.

最好的方法是在您的数据库中使用您的特定数据进行分析,以查看哪个更快.

我在1000000行的MySQL上尝试了两种方法.当列被索引时,性能上没有可辨别的差异 - 两者几乎是即时的.当列未编入索引时,我得到了以下结果:

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)
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下,使用OR的方法慢了大约30%.添加更多术语会使差异更大.结果可能因其他数据库和其他数据而异.

  • @inflagranti:不幸的是,没有优化器是完美的.优化器是非常复杂的程序,每个实现都有自己的优点和缺点.这就是为什么我说你应该对特定的实现进行分析.我想象`IN`方法的额外结构使得比一大堆可能相关的`OR`子句更容易优化.如果有一个"OR"方法更快的引擎,我会感到惊讶,但有时候OR速度较慢我并不感到惊讶. (27认同)
  • 如果优化器值得它的盐,它们应该执行相同的操作. (18认同)
  • @MarkByers优化器总是不能用`IN`替换多个`OR`? (2认同)

Pet*_*ang 35

最好的方法是查看执行计划.


我在Oracle上尝试过它,它完全一样.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );
Run Code Online (Sandbox Code Playgroud)

即使查询使用IN,执行计划也会说它使用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')                                              
Run Code Online (Sandbox Code Playgroud)

  • Oracle还有一个`INLIST ITERATOR`操作,如果有一个可以使用的索引,它会选择它.尽管如此,当我试用它时,"IN"和"OR"都会以相同的执行计划结束. (5认同)
  • 如果您要测试的值超过 3 个,Oracle 中会发生什么情况?您是否知道 Oracle 是否无法执行与 MySQL 相同的二分搜索优化,或者它在两种情况下都执行? (2认同)
  • @Mark Byers:我尝试了10个值的相同查询,结果仍然相同.请注意,优化程序按字母顺序使用了我的值.如果Oracle对该过滤器进行了一些内部优化,我不会感到惊讶...... (2认同)

sou*_*rge 6

我认为oracle足够聪明,可以将效率较低的那个(无论哪个)转换为另一个.所以我认为答案应该取决于每个人的可读性(我认为IN明显胜出的地方)


Ale*_*ssi 6

OR运算符需要比IN结构更复杂的评估过程,因为它允许许多条件,而不仅仅是像IN那样的等号.

以下是与OR一起使用的内容,但与IN不兼容:更大.更大或更小,更少,更少或相等,LIKE和更多像oracle REGEXP_LIKE.另外考虑条件可能并不总是比较相同的值.

对于查询优化器,它更容易管理IN运算符,因为它只是一个构造,它在多个条件下定义OR运算符,并且=运算符在相同的值上.如果你使用OR运算符,优化器可能不会认为你总是在相同的值上使用=运算符,如果它没有执行更深入和更复杂的详细说明,它可能会排除可能只有=所有相关条件下相同值的运算符,随后排除优化的搜索方法,如已经提到的二进制搜索.

[编辑]可能优化器可能无法实现优化的IN评估过程,但这并不排除一次可能发生(使用数据库版本升级).因此,如果您使用OR运算符,则不会在您的情况下使用优化精化.