等于 (=) 和具有一个文字值的 IN 之间的性能差异

Posted

技术标签:

【中文标题】等于 (=) 和具有一个文字值的 IN 之间的性能差异【英文标题】:Performance differences between equal (=) and IN with one literal value 【发布时间】:2016-10-16 03:40:38 【问题描述】:

当我们使用等号并且 IN 运算符具有相同的值时,SQL 引擎有何不同?执行时间有变化吗?

第一个使用相等检查运算符

WHERE column_value = 'All'

第二个使用IN 运算符和单个值

WHERE column_value IN ('All')

如果只有一个值,SQL 引擎是否会将 IN 更改为 =

mysql 和 PostgreSQL 有什么不同吗?

【问题讨论】:

不要试图学习数以百万计的规则,这意味着您将始终编写出绝对性能最佳的代码。编写清晰、简单、可理解的代码,这些代码显然会产生正确的结果。设定绩效目标。然后测量您的代码的性能。如果它表现得很好,继续前进。只有当它表现不佳时,你才应该花更多的时间在它上面。那时,尝试像您的问题中那样进行微不足道的更改,然后再次测量很简单。也许一个比另一个快,但是有很大的不同吗? 同意@Damien_The_Unbeliever。但有时我在用 SQL 写单行或单词时变得更加担心 它们有 99.9999999% 相同。只要你不做类似WHERE column_value IN ((select value from list_of_values where value = 'All' limit 1)) 的事情,你就可以了。子查询对in() 子句的性能造成巨大破坏。 @MonkeyZeus 由于 mysql 中基于成本的优化器(CBO),基于手头的问题,这也没有多少真相。 MS Sql Server 的类似问题sql statements with equals vs in 【参考方案1】:

这两个语句之间没有区别,当IN 中只有一个元素时,优化器会将IN 转换为=

尽管当您有这样的问题时,只需运行两个语句,运行它们的执行计划并查看差异。在这里 - 你不会找到任何东西。

在网上大量搜索后,我在 SQL 上找到了一个 document 来支持这一点(我假设它适用于所有 DBMS):

如果括号内只有一个值,这个推荐[sic]等价于,

WHERE "column_name" = 'value1

以下是 Oracle 中这两个查询的执行计划(大多数 DBMS 会以相同的方式处理):

EXPLAIN PLAN FOR
select * from dim_employees t
where t.identity_number = '123456789'

Plan hash value: 2312174735
-----------------------------------------------------
| Id  | Operation                   | Name          |
-----------------------------------------------------
|   0 | SELECT STATEMENT            |               |
|   1 |  TABLE ACCESS BY INDEX ROWID| DIM_EMPLOYEES |
|   2 |   INDEX UNIQUE SCAN         | SYS_C0029838  |
-----------------------------------------------------

对于IN()

EXPLAIN PLAN FOR
select * from dim_employees t
where t.identity_number in('123456789');

Plan hash value: 2312174735
-----------------------------------------------------
| Id  | Operation                   | Name          |
-----------------------------------------------------
|   0 | SELECT STATEMENT            |               |
|   1 |  TABLE ACCESS BY INDEX ROWID| DIM_EMPLOYEES |
|   2 |   INDEX UNIQUE SCAN         | SYS_C0029838  |
-----------------------------------------------------

如您所见,两者是相同的。这是在索引列上。未索引的列也是如此(只是全表扫描)。

【讨论】:

您对此有任何数据库的官方参考吗?我尝试搜索但没有找到。 @SomnathMuluk:- 我不认为 MySQL 对此有任何官方参考。如果您发现结果之间有任何差异,您可以创建一个测试用例并自行测试。 @RahulTripathi 我发现了一个关于 SQL 的文档,我想它适用于所有 DBMS。 我不久前查过这个,但没能找到任何关于这个的文件,很好的答案! 引用并非来自性能讨论。我认为这仅意味着“等效”,因为这两个语句具有相同的含义,并且没有对优化器提出任何要求。我仍然同意这肯定会被优化为相同的。【参考方案2】:

将它与单个值一起使用时没有区别。如果您检查上述两个查询的表扫描、索引扫描或索引查找,您会发现这两个查询之间没有区别。

Mysql 和 PostgresSQL 有区别吗?

不,这两个引擎没有任何区别(事实上,对于大多数数据库,包括 SQL Server、Oracle 等来说,它都是相同的)。两个引擎都会将IN 转换为=

【讨论】:

【参考方案3】:

对于单个 IN 子句,没有区别..下面是使用我拥有的 EMPS 表的演示..

select * from emps where empid in (1)
select * from emps where empid=1

执行计划中第一个查询的谓词:

[PerformanceV3].[dbo].[Emps].[empID]=CONVERT_IMPLICIT(int,[@1],0)

执行计划中第二个查询的谓词:

[PerformanceV3].[dbo].[Emps].[empID]=CONVERT_IMPLICIT(int,[@1],0)

如果 IN 子句中有多个值,最好将它们转换为连接

【讨论】:

【参考方案4】:

实际上并没有太大的区别,但是如果您的 column_value 被索引,IN 操作员可能不会将其读取为索引。

遇到过这个问题,小心点。

【讨论】:

这可能就是我一直在寻找的答案...【参考方案5】:

教人钓鱼等。以下是如何亲自查看查询的变化:

mysql> EXPLAIN SELECT * FROM sentence WHERE sentence_lang_id = "AMH"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: sentence
         type: ref
possible_keys: sentence_lang_id
          key: sentence_lang_id
      key_len: 153
          ref: const
         rows: 442
        Extra: Using where

让我们换一种方式试试:

mysql> EXPLAIN SELECT * FROM sentence WHERE sentence_lang_id in ("AMH")\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: sentence
         type: ref
possible_keys: sentence_lang_id
          key: sentence_lang_id
      key_len: 153
          ref: const
         rows: 442
        Extra: Using where

您可以阅读here 了解如何解释mysql EXPLAIN 请求的结果。现在,请注意我们得到了两个查询的相同输出:生成完全相同的“执行计划”。 type 行告诉我们查询使用了非唯一索引(在本例中为外键),ref 行告诉我们通过将常量值与该索引进行比较来执行查询。

【讨论】:

【参考方案6】:

只是补充一个不同的观点,rdbms 系统的主要观点之一是它们将为您重写您的查询,并为该查询和所​​有等效的查询选择最佳执行计划。这意味着只要两个查询在逻辑上相同,就应该始终在给定的 rdbms 上生成相同的执行计划。

话虽如此,许多查询是等效的(相同的结果集),但仅仅是因为数据库本身不知道的约束,所以要小心这些情况(例如,对于数字 1-6 的标志字段,数据库没有不知道<3in (1,2) 相同)。但归根结底,如果您只是考虑andor 语句的易读性,那么编写它们的方式不会对性能产生影响。

【讨论】:

以上是关于等于 (=) 和具有一个文字值的 IN 之间的性能差异的主要内容,如果未能解决你的问题,请参考以下文章

%in% 的对面:排除具有向量中指定值的行

第一个元素之间的差异小于或等于第二个元素的最小值的对的数量[关闭]

在 C++ 中创建具有 2 个双精度值的类

使用 keyof 提取仅具有特定类型值的键的字符串文字联合

具有许多不使用部分索引的值的 Postgres IN 子句

具有可为空值的 lambda 表达式 - 始终为 false,因为 Guid 类型的值从不等于“null”