MySQL 查询优化之 Index Merge

索引合并访问方法可以在查询中对一个表使用多个索引,对它们同时范围扫描,并且合并结果(intersects/unions/unions-of-intersections)。 此访问方法合并来自单个表的索引扫描; 它不会将扫描合并到多个表中。

使用索引合并的示例查询:

SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;SELECT * FROMtbl_nameWHERE (key1 = 10 OR key2 = 20) AND non_key = 30;SELECT * FROMt1, t2WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%')AND t2.key1 =t1.some_col;SELECT * FROMt1, t2WHERE t1.key1 = 1

AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2);

【注意】

索引合并优化算法有以下已知的缺陷:

如果您的查询具有深度AND或OR嵌套的复杂WHERE子句,并且MySQL不选择最佳计划,请尝试使用以下标识转换来分配条件:

(x AND y) OR z => (x OR z) AND (y ORz)

(xOR y) AND z => (x AND z) OR (y AND z)

索引合并不适用于全文索引。

在EXPLAIN输出中,索引合并方法在type列中显示为index_merge。 在这种情况下,key列包含使用的索引列表,key_len包含这些索引的最长键部分列表。

Index Merge访问方法有几种算法,它们显示在EXPLAIN输出的Extra字段中:

Using intersect(...)

Using union(...)

Using sort_union(...)

Index Merge方法根据合并算法的不同分成了三种:Intersect,Union,Sort_union。它们显示在EXPLAIN输出的Extra字段中。Intersect和Union都需要使用的索引是ROR的,也就是ROWID ORDERED,即针对不同的索引扫描出来的数据必须是同时按照ROWID排序的,这里的ROWID其实也就是InnoDB的主键(如果不定义主键,InnoDB会隐式添加ROWID列作为主键)。只有每个索引是ROR的,才能进行归并排序,你懂的。 当然你可能会有疑惑,查记录后内部进行一次sort不一样么,何必必须要ROR呢,不错,所以有了Sort-union。Sort-union就是每个非ROR的索引排序后再进行Merge。MySQL至于为什么没有Sort-Intersect,就不清楚了,但是MariaDB从5.3版本开始就支持了。

1. Index Merge Intersection 访问算法

index intersect merge是多个索引条件扫描得到的结果进行交集运算。显然在多个索引提交之间是 AND 运算时,才会出现 index intersect merge。 下面两种where条件或者它们的组合时会进行 index intersect merge:

条件使用到复合索引中的所有字段或者左前缀字段(对单字段索引也适用)

key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN

主键上的任何范围条件

SELECT * FROMinnodb_tableWHERE primary_key < 10 AND key_col1 = 20;SELECT * FROMtbl_nameWHERE key1_part1 = 1 AND key1_part2 = 2 AND key2 = 2;

示例1

mysql> show index fromemployees;+-----------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |

+-----------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| employees | 0 | PRIMARY | 1 | emp_no | A | 298936 | NULL | NULL | | BTREE | | |

| employees | 1 | idx_name | 1 | last_name | A | 1651 | NULL | NULL | | BTREE | | |

| employees | 1 | idx_first_name | 1 | first_name | A | 1251 | NULL | NULL | | BTREE | | |

+-----------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

3 rows in set (0.00sec)

mysql> explain select * from employees.employees e where e.first_name='Tzu' and e.last_name='Terkki';+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+-------------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+-------------------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | idx_name,idx_first_name | idx_name,idx_first_name | 66,58 | NULL | 1 | 100.00 | Using intersect(idx_name,idx_first_name); Using where |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+-------------------------------------------------------+

1 row in set, 1 warning (0.00 sec)

示例2

mysql> show index fromemployees;+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |

+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| employees | 0 | PRIMARY | 1 | emp_no | A | 298936 | NULL | NULL | | BTREE | | |

| employees | 1 | idx_name | 1 | last_name | A | 1651 | NULL | NULL | | BTREE | | |

+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

2 rows in set (0.00sec)

mysql> explain select * from employees.employees e where e.emp_no>10011 and e.last_name = 'Terkki';+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | PRIMARY,idx_name | idx_name,PRIMARY | 70,4 | NULL | 90 | 100.00 | Using intersect(idx_name,PRIMARY); Using where |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+------------------------------------------------+

1 row in set, 1 warning (0.00 sec)

索引合并Intersection访问算法对所有使用的索引执行同时扫描,并产生从合并索引扫描中接收到的行序列的交集。

如果查询中使用的所有列都被使用的索引覆盖,则不会检索完整的表行(EXPLAIN输出包含在这种情况下在Extra字段中 Using index)。 例如:

mysql> explain select count(*) from employees.employees e where e.first_name='Tzu' and e.last_name='Terkki';+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | idx_name,idx_first_name | idx_name,idx_first_name | 66,58 | NULL | 1 | 100.00 | Using intersect(idx_name,idx_first_name); Using where; Using index |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

mysql> explain select e.emp_no,e.first_name,e.last_name from employees.employees e where e.first_name='Tzu' and e.last_name='Terkki';+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | idx_name,idx_first_name | idx_name,idx_first_name | 66,58 | NULL | 1 | 100.00 | Using intersect(idx_name,idx_first_name); Using where; Using index |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+--------------------------------------------------------------------+

1 row in set, 1 warning (0.00 sec)

如果使用的索引未涵盖查询中使用的所有列,则仅在满足所有使用的键的范围条件时才检索完整行。

如果其中一个合并条件是InnoDB表的主键上的条件,则它不用于行检索,而是用于过滤掉使用其他条件检索的行。

2. Index Merge Union 访问算法

index uion merge就是多个索引条件扫描,对得到的结果进行并集运算,显然是多个条件之间进行的是 OR 运算。

下面几种类型的 where 条件,以及他们的组合可能会使用到index union merge算法:

条件使用到复合索引中的所有字段或者左前缀字段(对单字段索引也适用)

key_part1 = const1 AND key_part2 = const2 ... AND key_partN = constN

InnoDB表的主键上的任何范围条件

任何符合 index intersect merge 的where条件

SELECT * FROMt1WHERE key1 = 1 OR key2 = 2 OR key3 = 3;SELECT * FROMinnodb_tableWHERE (key1 = 1 AND key2 = 2)OR (key3 = 'foo' AND key4 = 'bar') AND key5 = 5;

示例3

mysql> explain select e.emp_no,e.first_name,e.last_name from employees.employees e where e.first_name='Tzu' or e.last_name='Terkki';+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+---------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+---------------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | idx_name,idx_first_name | idx_first_name,idx_name | 58,66 | NULL | 416 | 100.00 | Using union(idx_first_name,idx_name); Using where |

+----+-------------+-------+------------+-------------+-------------------------+-------------------------+---------+------+------+----------+---------------------------------------------------+

1 row in set, 1 warning (0.00 sec)

示例4

mysql> explain select * from employees.employees e where e.emp_no>10011 or e.last_name = 'Terkki';+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+--------+----------+--------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+--------+----------+--------------------------------------------+

| 1 | SIMPLE | e | NULL | index_merge | PRIMARY,idx_name | PRIMARY,idx_name | 4,66 | NULL | 149648 | 100.00 | Using union(PRIMARY,idx_name); Using where |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+--------+----------+--------------------------------------------+

1 row in set, 1 warning (0.00 sec)

3. Index Merge Sort-Union 访问算法

当WHERE子句转换为OR组合的多个范围条件时,此访问算法适用,但Index Merge union 算法不适用。

SELECT * FROMtbl_nameWHERE key_col1 < 10 OR key_col2 < 20;SELECT * FROMtbl_nameWHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col = 30;

sort-union算法和union算法之间的区别在于sort-union算法必须首先获取所有行的行ID,然后在返回任何行之前对它们进行排序。

mysql> show index fromt1;+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |

+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| t1 | 1 | idx_i1_i2 | 1 | i1 | A | 5 | NULL | NULL | | BTREE | | |

| t1 | 1 | idx_i1_i2 | 2 | i2 | A | 25 | NULL | NULL | | BTREE | | |

| t1 | 1 | idx_i2 | 1 | i2 | A | 5 | NULL | NULL | | BTREE | | |

+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

3 rows in set (0.00sec)

mysql> explain select * from t1 force index (idx_i1_i2,idx_i2) where i1>1 or i2>5;+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

| 1 | SIMPLE | t1 | NULL | index_merge | idx_i1_i2,idx_i2 | idx_i1_i2,idx_i2 | 4,4 | NULL | 21 | 100.00 | Using sort_union(idx_i1_i2,idx_i2); Using where |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

1 row in set, 1 warning (0.00sec)

mysql> explain select * from t1 force index (idx_i1_i2,idx_i2)where (i1>4 or i2=4) and d = '2001-01-01';+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

| 1 | SIMPLE | t1 | NULL | index_merge | idx_i1_i2,idx_i2 | idx_i1_i2,idx_i2 | 4,4 | NULL | 10 | 10.00 | Using sort_union(idx_i1_i2,idx_i2); Using where |

+----+-------------+-------+------------+-------------+------------------+------------------+---------+------+------+----------+-------------------------------------------------+

1 row in set, 1 warning (0.00 sec)

4. 参考文档

mysql merge查询速度_MySQL 查询优化之 Index Merge相关推荐

  1. mysql 设置查询变量_MySQL查询优化--调整内部变量的详解

    MySQL是如此的开放,所以可轻松地进一步调整其缺省设置以获得更优的性能及稳定性.需要优化的一些关键变量如下: 改变索引缓冲区长度(key_buffer) 一般,该变量控制缓冲区的长度在处理索引表(读 ...

  2. mysql 子查询代替_MySQL查询优化:用子查询代替非主键连接查询

    一对多的两张表,一般是一张表的外键关联到另一个表的主键.但也有不一般的情况,也就是两个表并非通过其中一个表的主键关联. 一对多的两张表,一般是一张表的外键关联到另一个表的主键.但也有不一般的情况,也就 ...

  3. Mysql中查询速度的优化

    2019独角兽企业重金招聘Python工程师标准>>> mysql中查询速度的优化 1.查看每一个表的数据量 2.left join的时候尽量减少表的大小,通过临时表,查询条件去限制 ...

  4. mysql 慢查询过多_MySQL 慢查询优化

    为什么查询速度会慢 1.慢是指一个查询的响应时间长.一个查询的过程: 客户端发送一条查询给服务器 服务器端先检查查询缓存,如果命中了缓存,则立可返回存储在缓存中的结果.否则进入下一个阶段 服务器端进行 ...

  5. mysql 慢查询毫秒_Mysql 慢查询优化实践

    Mysql 慢查询优化实践 目标: 提高mysql运行效率,增加并发,提高响应速度 方案: 通过阿里云给的慢查询日志excel,对耗时长,开销大的sql语句进行优化,提升访问速度服务器运行效率 实践: ...

  6. mysql+index组合索引_MySQL 优化之 index merge(索引合并)

    标签: MySQL5.0之前,一条语句中一个表只能使用一个索引,无法同时使用多个索引.但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引.理解了 index mer ...

  7. mysql 视图 查询速度慢_mysql 视图查询速度慢

    场景: 表 stockpooldata_flash CREATE TABLE `stockpooldata_flash` ( `id` bigint(15) NOT NULL AUTO_INCREME ...

  8. mysql text 查询速度_数据库学习之让索引加快查询速度(四)

    数据库学习之让索引加快查询速度 目录 索引简介 mysql的索引分类 创建索引 添加与删除索引 索引简介 索引在MySQL中也叫做"键",是存储引擎用于快速找到记录的一种数据结构. ...

  9. mysql严重查询速度的问题一则

    之前用mysql一直也没觉得有特别慢的感觉,最近发现新开发的系统有个页面打开速度非常慢,有时候1分钟都打不开.查了一下系统,定位到是一条sql语句执行慢造成的.该sql如下: SELECT COUNT ...

最新文章

  1. 别再傻傻地用这些软件G转P了,修复后不稳定的真相在这里
  2. 填平新版本Xcode安装插件不成功的坑
  3. 从安全测试开始:与杰夫•佩恩的一场面谈(译)
  4. 【PostgreSQL+PostGIS离线安装】2天的踩坑及问题解决经验分享(含安装文件postgresql-9.5.9+postgis-2.2.3+多个依赖及测试SQL)
  5. g++ linux 编译开栈_Linux下编写C++服务器(配置C++编译调试环境)
  6. java中矩阵怎么打印_在Java编程中打印二维数组或矩阵
  7. mysql 事件 day hour_Mysql事件调度器(Event Scheduler)
  8. html自定义滚动条不占位,如何实现滚动条在各浏览器中不占用布局
  9. android 判断 string 是否是字母数字,Android中判断字符串中必须包含字母或者数字...
  10. 一个RSS阅读器的源码,不敢独享!
  11. 看完微软大神写的 求平均值代码,我意识到自己还是 too young 了
  12. 找出一个字符串中的数字
  13. Excel 英文切换大小写;Excel 中去除重复项
  14. GokeAudio是一款简约小巧的开源安卓SIP软电话客户端
  15. matlab videoToFrames 视频切割成帧
  16. 西南大学通信学硕成功上岸,初试专业课113分(专业课最高分)
  17. 康拓普:数据可视化如何让大数据更加人性化?
  18. Base58算法加密解密(Python实现)
  19. mysql rollup函数_Mysql,Oracle使用rollup函数完成行列统计
  20. Diffusion Model

热门文章

  1. android 设置EditText光标位置
  2. 利用github for windows 工具将本地的内容同步到github上
  3. php开发环境配置 iis6+php-5.2.1-Win32+mysql-5.0.18-win32+phpMyAdmin-2.7.0-pl2快速安装
  4. ASP.Net页面保存持久数据的几种方法比较
  5. 线程 pthread_create Linux函数 线程创建
  6. android p ify 三星,Enjarify - Android逆向(二)
  7. 理解Android Framework
  8. Android SurfaceView双缓存
  9. mysql之查询用户名
  10. 深度学习自学(三十三):通过结构正则化深度聚类解决无监督域自适应问题