索引合并优化
官网翻译
MySQL5.7文档 索引合并是为了减少几个范围(type中的range类型:range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, or IN() operators:)扫描的行数,并将他们的结果合并成一个。这里的合并可能是, 他们的并集、交集或者几个交集后的并集。这种索引的合并只能合并一个表中的索引扫描;而不能合并 多个表种的范围扫描。
在explain的输出中,索引合并将会在type列出现,显示为index merge
。在这种case中,key列包含合并的索引的 一个列表,并且key_len列包含这些索引中最长的key的部分。
例如:
索引合并方法有几种合并算法(见explain输出的extra列)
- Using intersect(...)
- Using union(...)
- Using sort_union(...)
下面的小节会更详细的介绍这些算法。
注意
索引合并算法有以下已知的缺陷
如果你的查询使用的是一个带有多层and/or嵌套的复杂where子句, MySQL就不会选择这个优化策略了,你可以尝试使用一下规则来拆分他们:
索引合并还不能应用到全文检索上。但未来的MySQL版本可能会支持
具体是使用索引合并优化,还是其他的优化方法?MySQL要根据他的代价估算模型来决定。
1. 通过Intersection算法合并索引
这个算法会被使用,当where子句可以被转换为几个排列情况,使用and来组合不同的key,并且每一个组合都要下面的一种:
- 在这种形式中,索引要有确切的N部分(即,所有的索引列都要覆盖)
key_part1=const1 AND key_part2=const2 ... AND key_partN=constN
- InnoDB表中主键的任何范围条件
例如:
这个Intersection合并索引算法会同时扫描所有使用索引,并产出:(合并的索引)(所扫描的行序列)的交集。
如果要查询的所有的列都在被合并的索引上,就不会扫描表中的所有列了(即被索引覆盖了,在explain的输出 中在extra列就会显示Using index)。下面是一个例子:
如果使用的索引没有覆盖所有的查询列,就会根据具体条件回表查询全部的数据行列了。
If one of the merged conditions is a condition over a primary key of an InnoDB table, it is not used for row retrieval, but is used to filter out rows retrieved using other conditions.
2. 通过Union算法合并索引
这个算法的使用条件和Intersection算法差不多。这个算法使用到,where子句可以别转换为使用or来组合 不同的key,并且每一个组合都要下面的一种:
- 在这种形式中,索引要有确切的N部分(即,所有的索引列都要覆盖)
key_part1=const1 AND key_part2=const2 ... AND key_partN=constN
- InnoDB表中主键的任何范围条件
- 索引合并的intersect算法能使用的情况也行
例如:
3. 通过sort_union算法合并索引
这中算法会在,使用or来排列条件,但是union算法又不适用的情况
例如:
sort_union算法和union算法的不同之处在于:sort_union算法在返回结果之前必须获得所有行的行ID,并且将他们排序。
参考:
[1]:[http://www.tuicool.com/articles/eyURR3r]
[2]:[http://www.orczhou.com/index.php/2013/01/mysql-source-code-query-optimization-index-merge/]
[3]:[http://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html]