MySQL/PostgreSQL中IN关键字的速度

Sas*_*gov 9 mysql postgresql performance list

我听说很多人都说IN大多数关系数据库中的关键字很慢.这是真的吗?一个示例查询就是这个,从头到尾:

SELECT * FROM someTable WHERE someColumn IN (value1, value2, value3)
Run Code Online (Sandbox Code Playgroud)

我听说这比这样做慢得多:

SELECT * FROM someTable WHERE
  someColumn = value1 OR
  someColumn = value2 OR
  someColumn = value3
Run Code Online (Sandbox Code Playgroud)

这是真的?或者速度差是否可以忽略不计?如果重要的话,我正在使用PostgreSQL,但我也想知道MySQL如何运行(如果它有任何不同).提前致谢.

Gre*_*ith 13

在PostgreSQL中,你在这里得到的确切取决于底层表,所以你应该对一些有用的数据子集使用EXPLAIN ANALYZE进行一些示例查询,以确定优化器将要做什么(确保表格你"反对运行也一直在分析".IN可以通过几种不同的方式处理,这就是为什么你需要查看一些样本来确定哪种替代方法用于你的数据.你的问题没有简单的通用答案.

至于您在修订版中添加的具体问题,针对这里没有涉及索引的简单数据集,您将获得两个查询计划的示例:

postgres=# explain analyze select * from x where s in ('123','456');
 Seq Scan on x  (cost=0.00..84994.69 rows=263271 width=181) (actual time=0.015..1819.702 rows=247823 loops=1)
   Filter: (s = ANY ('{123,456}'::bpchar[]))
 Total runtime: 1931.370 ms

postgres=# explain analyze select * from x where s='123' or s='456';
 Seq Scan on x  (cost=0.00..90163.62 rows=263271 width=181) (actual time=0.014..1835.944 rows=247823 loops=1)
   Filter: ((s = '123'::bpchar) OR (s = '456'::bpchar))
 Total runtime: 1949.478 ms
Run Code Online (Sandbox Code Playgroud)

这两个运行时基本相同,因为实际处理时间由表中的顺序扫描决定; 多次运行显示两者之间的差异低于运行运行误差范围.正如您所看到的,PostgreSQL将IN情况转换为使用其ANY过滤器,该过滤器应始终比一系列OR更快地执行.同样,这个微不足道的案例并不一定代表您在涉及索引等的严肃查询中会看到的内容.无论如何,用一系列OR语句手动替换IN应该永远不会更快,因为如果有优秀的数据可用,优化器知道最好的事情.

一般来说,PostgreSQL比MySQL优化器知道更多关于如何优化复杂查询的技巧,但它也很大程度上依赖于你给优化器提供了足够的数据.PostgreSQL wiki的"性能优化"部分的第一个链接涵盖了从优化器获得良好结果所需的最重要的事情.


Qua*_*noi 8

MySQL,这些是优化器的完整同义词:

SELECT  *
FROM    someTable
WHERE   someColumn IN (value1, value2, value3)
Run Code Online (Sandbox Code Playgroud)

SELECT  *
FROM    someTable
WHERE   someColumn = value1 OR
        someColumn = value2 OR
        someColumn = value3
Run Code Online (Sandbox Code Playgroud)

,只要它value是文字内容或预设变量.

根据文件:

单部分索引的范围条件的定义如下:

  • 对于这两种BTREEHASH索引,使用时具有恒定值的关键部分的比较是一个范围条件=,<=>,IN(),IS NULL,或IS NOT NULL运营商.
  • ...
  • 对于所有类型的索引,多个范围条件与范围条件组合ORAND形成范围条件.

前面描述中的"常量值"表示以下之一:

  • 来自查询字符串的常量
  • 来自同一连接的const或系统表的列
  • 不相关子查询的结果
  • 任何表达式完全由前面类型的子表达式组成

但是,这个查询:

SELECT  *
FROM    table
WHERE   id = 1
        OR id = (SELECT id FROM other_table WHERE unique_condition)
Run Code Online (Sandbox Code Playgroud)

将使用索引id,而这一个:

SELECT  *
FROM    table
WHERE   id IN (1, (SELECT id FROM other_table WHERE unique_condition))
Run Code Online (Sandbox Code Playgroud)

将使用fullscan.

I. e.当其中一个value是单行子查询时,存在差异.

我最近提交它的bug 45145MySQL(它原来是5.2具体的,在缺席5.1和纠正中6.0)


Bre*_*ley 5

使用IN不一定很慢,这就是你如何构建IN参数,这将大大减慢速度.人们经常使用SELECT ... WHERE x IN(SELECT ...,它可能非常优化(即根本没有).搜索"相关子查询"以查看它有多糟糕.

通常,您根本不必使用IN,而是可以使用JOIN,并利用派生表.

SELECT * FROM table1 WHERE x IN (SELECT y FROM table2 WHERE z=3)
Run Code Online (Sandbox Code Playgroud)

可以这样改写

SELECT * FROM table1 JOIN (SELECT y FROM table2 WHERE z=3) AS table2 ON table1.x=table2.y
Run Code Online (Sandbox Code Playgroud)

如果IN语法很慢,JOIN语法通常会快得多.您可以使用EXPLAIN查看每个查询的优化方式.这是一个简单的示例,您的数据库可能会显示相同的查询路径,但更复杂的查询通常会显示不同的内容.