如果没有索引合并, 则在多个单列索引中优化器只会选取最有的一个索引使用, 其余的索引将舍弃
根据官方文档中的说明,我们可以了解到:
1、索引合并是把几个索引的范围扫描合并成一个索引。
2、索引合并的时候,会对索引进行并集,交集或者先交集再并集操作,以便合并成一个索引。
3、这些需要合并的索引只能是一个表的。不能对多表进行索引合并。
怎么确定使用了索引合并
在使用explain对sql语句进行操作时,如果使用了索引合并,那么在输出内容的type列会显示 index_merge,key列会显示出所有使用的索引。如下:
使用索引合并的示例
数据表结构
mysql> show create table test\G
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key1_part1` int(11) NOT NULL DEFAULT '0',
`key1_part2` int(11) NOT NULL DEFAULT '0',
`key2_part1` int(11) NOT NULL DEFAULT '0',
`key2_part2` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `key1` (`key1_part1`,`key1_part2`),
KEY `key2` (`key2_part1`,`key2_part2`)
) ENGINE=MyISAM AUTO_INCREMENT=18 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
数据
mysql> select * from test;
+----+------------+------------+------------+------------+
| id | key1_part1 | key1_part2 | key2_part1 | key2_part2 |
+----+------------+------------+------------+------------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 2 | 1 |
| 3 | 1 | 1 | 2 | 2 |
| 4 | 1 | 1 | 3 | 2 |
| 5 | 1 | 1 | 3 | 3 |
| 6 | 1 | 1 | 4 | 3 |
| 7 | 1 | 1 | 4 | 4 |
| 8 | 1 | 1 | 5 | 4 |
| 9 | 1 | 1 | 5 | 5 |
| 10 | 2 | 1 | 1 | 1 |
| 11 | 2 | 2 | 1 | 1 |
| 12 | 3 | 2 | 1 | 1 |
| 13 | 3 | 3 | 1 | 1 |
| 14 | 4 | 3 | 1 | 1 |
| 15 | 4 | 4 | 1 | 1 |
| 16 | 5 | 4 | 1 | 1 |
| 17 | 5 | 5 | 1 | 1 |
| 18 | 5 | 5 | 3 | 3 |
| 19 | 5 | 5 | 3 | 1 |
| 20 | 5 | 5 | 3 | 2 |
| 21 | 5 | 5 | 3 | 4 |
| 22 | 6 | 6 | 3 | 3 |
| 23 | 6 | 6 | 3 | 4 |
| 24 | 6 | 6 | 3 | 5 |
| 25 | 6 | 6 | 3 | 6 |
| 26 | 6 | 6 | 3 | 7 |
| 27 | 1 | 1 | 3 | 6 |
| 28 | 1 | 2 | 3 | 6 |
| 29 | 1 | 3 | 3 | 6 |
+----+------------+------------+------------+------------+
29 rows in set (0.00 sec)
使用索引合并的案例
mysql> explain select * from test where (key1_part1=4 and key1_part2=4) or key2_part1=4\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
type: index_merge
possible_keys: key1,key2
key: key1,key2
key_len: 8,4
ref: NULL
rows: 3
Extra: Using sort_union(key1,key2); Using where
1 row in set (0.00 sec)
未使用索引合并的案例
mysql> explain select * from test where (key1_part1=1 and key1_part2=1) or key2_part1=4\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: test
type: ALL
possible_keys: key1,key2
key: NULL
key_len: NULL
ref: NULL
rows: 29
Extra: Using where
1 row in set (0.00 sec)
从上面的两个案例大家可以发现,相同模式的sql语句,可能有时能使用索引,有时不能使用索引。是否能使用索引,取决于mysql查询优化器对统计数据分析后,是否认为使用索引更快。因此,单纯的讨论一条sql是否可以使用索引有点片面,还需要考虑数据
索引合并(Index Merge)访问方法有几种算法,这些算法显示在EXPLAIN输出的Extra 字段中:
Using intersect(…)
Using union(…)
Using sort_union(…)
以下部分将更详细地介绍这些算法。 优化器根据各种可用选项的成本估计,在不同的可能的索引合并算法和其他访问方法之间进行选择。
索引合并(Index Merge)的使用取决于optimizer_switch系统变量的index_merge,index_merge_intersection,index_merge_union和index_merge_sort_union标志的值。默认情况下,所有这些标志都打开。 要仅启用特定算法,请将index_merge设置为关闭,并仅启用其他应允许的其他算法。
1.索引合并Intersection访问算法(The Index Merge Intersection Access Algorithm)
这个访问算法适用于WHERE子句在与AND结合的不同键上被转换为几个范围条件,并且每个条件是以下之一:
这种形式的N部分表达式,其索引正好具有N个部分(即所有索引部分都被覆盖):
key_part1 = const1 AND key_part2 = const2 ... 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;
索引合并Intersection访问算法对所有使用的索引执行同时扫描,并产生从合并索引扫描中接收到的行序列的交集。
如果查询中使用的所有列都被使用的索引覆盖,则不会检索完整的表行(EXPLAIN输出包含在这种情况下在Extra字段中 Using index)。 这是一个这样的查询的例子:
SELECT COUNT(*) FROM t1 WHERE key1 = 1 AND key2 = 1;
如果使用的索引不包括查询中使用的所有列,则只有满足所有使用的键的范围条件时才检索完整的行。
如果其中一个合并条件是InnoDB表的主键条件,则不用于行检索,而是用于过滤使用其他条件检索的行。
2.索引合并Union访问算法(The Index Merge Union Access Algorithm)
该算法的标准与索引合并Intersection访问算法相似。 当将表的WHERE子句转换由OR组合的不同键上的几个范围条件时,该算法是适用的,并且每个条件是以下之一:
这种形式的N部分表达式,其索引正好具有N个部分(即所有索引部分都被覆盖):
key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN
InnoDB表通过主键的任何范围条件。
索引合并Intersection访问算法适用的条件。
例如:
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;
3.索引合并Sort-Union访问算法(The Index Merge Sort-Union Access Algorithm)
当WHERE子句被转换为由OR组合的几个范围条件时,该访问算法是适用的,但索引合并Union访问算法不适用。
例如:
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,然后在返回任何行之前对其进行排序。