MySQL索引合并优化

如果没有索引合并, 则在多个单列索引中优化器只会选取最有的一个索引使用, 其余的索引将舍弃

根据官方文档中的说明,我们可以了解到:

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,然后在返回任何行之前对其进行排序。

猜你喜欢

转载自blog.csdn.net/asdfsadfasdfsa/article/details/83016794