索引合并(Index Merge)访问方法用多个区间扫描获取记录,并将它们合并到一个结果集中。这种访问方法只合并来自同一张表的索引,而不是多张表。合并结果可以是底层扫描区间的并集,交集,或交集的并集。
下面展示了一个可能会用到Index Merge的例子:
select * from tbl_name where key1 = 10 or key2 = 20;
select * from tbl_name where (key1 = 10 or key2 = 20) and non_key = 30;
select * from t1, t2
where (t1.key1 in(1, 2) or t1.key2 like 'value%')
and t2.key1 = t1.some_col;
select * from t1, t2
where t1.key1 = 1
and (t2.key1 = t1.some_col or t2.key2 = t1.some_col2);
索引合并算法有以下不足:
- 如果查询的where条件很复杂,and/or连接的深度很深,MySQL没有选择最优执行计划,可以尝试使用下面的转换将查询条件分解:
(x and y) or z => (x or z) and (y or z) (x or y) and z => (x and z) or (y and z)
- 索引合并不适用于全文索引。
如果使用了索引合并,Explain的输出中,type列会显示index merge。这种场景中,key列会显示使用的多个索引,key_len会包含这些索引的最长前缀和。
索引合并访问方法有多个算法,都展示在explain输出结果中的Extra列中:
- Using intersect(…)
- Using union(…)
- Using sort_union(…) 下面的章节将会更详细的介绍这些算法。查询优化器将会给予成本评估,判断是选择可能的索引合并算法还是其它访问方法。
- Index Merge Intersection 访问方法
- Index Merge Union 访问方法
- Index Merge Sort-Union 访问方法
- Influencing Index Merge优化
Index Merge Intersection 访问方法 #
当where条件被转换成多个不同key上的区间条件(and连接)且每一个条件都是下列情形之一时,会使用这种算法:
- N列表达式,索引刚好有N个部分(就是说,覆盖了索引的所有部分):
key_part1 = const1 and key_part2 = const2 and ... and key_partN = constN
- 有条件是一张InnoDB表的主键列。 例如:
select * from innodb_table
where primary_key < 10 and key_col1 = 20;
select * from tbl_name
where key1_part1 = 1 and key1_part2 = 2 and key2 = 2;
索引合并算法会在所有用到的索引上进行扫描,并生成交集。 如果查询中用到的所有列都在用到的索引中,就不会进行全表扫描(explain输出结果的Extra字段会出现Using index)。下面是一个这种查询的例子:
select count(*) from t1 where key1 = 1 and key2 = 1;
如果用到的索引没有覆盖查询中用到的所有列,只有当所有范围条件都被满足时才会回表。
如果有一个被合并的条件是一张InnoDB表的主键,它不会被用于回表,但是会被用于过滤其它条件差生的结果集。
Index Merge Union 访问方法 #
这种索引合并算法的标准和索引合并交集算法类似。只有当where条件被转换成多个不同key上的区间条件(or连接)且每一个条件都是下列情形之一时,会使用这种算法:
- N列表达式,索引刚好有N个部分(就是说,覆盖了索引的所有部分):
key_part1 = const1 or key_part2 = const2 ... or key_partN = constN
- 有条件是一张InnoDB表的主键列。
- 某个条件可以使用索引合并算法。 例如:
select * from t1
where key1 = 1 or key2 = 2 or key3 = 3;
select * from innodb_table
where (key1 = 1 and key2 = 2)
or (key3 = 'foo' and key4 = 'bar') and key5 = 5;
Index Merge Sort-Union 访问方法 #
当where条件被转变成or连接的多个区间条件,但是却不适用于索引合并扫描算法时,会使用这种算法。 例子:
select * from tbl_name
where key_col1 < 10 or key_col2 < 20;
select * from tbl_name
where (key_col1 > 10 or key_col2 = 20) and nonkey_col=30;
sort-union算法和union算法的不同是:在返回结果集之前,sort-union算法必须要获取所有记录的id,再用这些id获取所有的记录,并对其进行排序。
Influencing Index Merge优化 #
索引合并的使用受系统变量optimizer_switch的几个标志的控制:index_merge,index_merge_intersection,index_merge_union,index_merge_sort_union。请查阅章节8.9.2 “Switchable Optimizations”。这些标志默认都是on。如果只想开启特定算法,将index_merge设置成off,并只将其它要使用的标志设置成on。
除了使用optimizer_switch系统变量来控制会话级别的索引合并算法外,MySQL还支持通过优化器提示来在语句级别上影响索引合并的使用。请查阅章节8.9.3 “Optimizer Hints”。