是什么使优化器停止使用索引?

时间:2020-04-23 05:50:16

标签: mysql

假设我有一个带有主键的表A

PRIMARY KEY(c1,c2)

c1的基数非常低,而c2的基数非常高

执行以下查询时,

select *
from A
where (c1, c2) in (('001', 'aaa'))


select *
from A
where c1 = '001'and c2 = 'aaa'

优化器使用索引。

但是,在以下情况下,

案例1:

select *
from A
where (c1, c2) in (('001', 'aaa'), ('002', 'bbb'), ('003', 'ccc'))

案例2:

select *
from A
where (c1 = '001'and c2 = 'aaa') or
      (c1 = '002'and c2 = 'bbb') or
      (c1 = '003'and c2 = 'ccc')

优化器停止对案例1使用索引,但仍对案例2使用

是什么使优化器停止使用案例1的索引?

* MySQL版本:5.6.10

1 个答案:

答案 0 :(得分:3)

尽管这些表达式在语义上是等效的,但MySQL仅在Range Optimization of Row Constructor Expressions(强调我的名字)中添加了MySQL 5.7.3,实际上能够以相同的方式执行它们:

优化器立即能够将范围扫描访问方法应用于以下形式的查询:

SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));

以前,要使用范围扫描,必须将查询写为:

SELECT ... FROM t1 WHERE ( col_1 = 'a' AND col_2 = 'b' )
  OR ( col_1 = 'c' AND col_2 = 'd' );

要使优化器使用范围扫描,查询必须满足以下条件:

  • 仅使用IN()谓词,而不使用NOT IN()。
  • 在IN()谓词的左侧,行构造函数仅包含列引用。
  • 在IN()谓词的右侧,行构造器仅包含运行时常量,这些常量是在执行过程中绑定到常量的文字或本地列引用。
  • 在IN()谓词的右侧,有个以上的行构造器