假设我有一个带有主键的表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
答案 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()谓词的右侧,有个以上的行构造器。