Index Merge特性

在MySQL 5.5之前版本中,查询或子查询被限制在一个表只能使用一个索引(回表查询除外)。

假设表TB1001上C1和C2列分别有单列索引,如对下面查询:

SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX';

单独使用任一索引都无法获取到所有满足条件的数据,因此查询只能使用全表扫描。

在MySQL 5.5版本中引入Index Merge特性,允许:
查询对一个表上多个索引进行范围扫描并将多个扫描结果进行合并(UNION/INTERSECT)。

Index Merge三种合并算法:

1、Index Merge Intersect:对多个结果集求交集
2、Index Merge Union:对多个结果集求UNION集合(无需对结果集排序)
3、Index Merge Sort-Union:对多个结果集先排序再求UNION集合

Index Merge Intersect算法

当查询过滤条件(WHERE部分)上使用AND关联多个不同KEY的过滤条件时,如:

# 表TB1001有主键索引PRIMARY KEY(ID)
# 表TB1001有辅助索引IDX_C1(C1) 和辅助索引IDC_C2(C2) SELECT * FROM TB1001 WHERE C1='XXX' AND C2='XXX';

不使用Index Merge Intersect算法时执行计划伪代码为:

SELECT * FROM TB1001
WHERE ID IN (
SELECT ID FROM TB1001 WHERE C1='XXX')
AND C2='XXX';

使用Index Merge Intersect算法时执行计划伪代码为:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
INTERSECT
SELECT ID FROM TB1001 WHERE C2='XXX'
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID;

操作成本假设1:

假设:
满足C1='XXX'的记录有10000行:索引IDX_C1上每个数据页存放500行索引记录,满足条件数据:
A、"顺序存放"在索引IDX_C1上"连续"的20个索引页中。
B、"分散存放"在主键上"随机"的2000个数据页中。
满足C2='XXX'的记录有20000行,索引IDX_C2上每个数据页存放500行索引记录,满足条件数据:
A、"顺序存放"在索引IDX_C2上"连续"的40个索引页中。
B、"分散存放"在主键上"随机"的4000个数据页中。
同时满足C1='XXX' AND C2='XXX'的记录有200行,满足条件数据:
A、"分散存放"在主键上"随机"的40个数据页中 那么:
1、不使用Index Merge Intersect算法需要"顺序读取"20个IDX_C1索引页+"随机读取"2000个主键索引数据页
2、使用Index Merge Intersect算法需要"顺序读取"20个IDX_C1索引页+"顺序读取"40个IDX_C2索引页+"随机读取"40个主键索引数据页
针对上面情况,使用Index Merge Intersect算法能有效降低对主键的回表查找次数和随机读取次数(从2000次下降至40次)。

操作成本假设2:

假设:
满足C1='XXX'的记录有20行:索引IDX_C1上每个数据页存放500行索引记录,满足条件数据:
A、"顺序存放"在索引IDX_C1上"连续"的1个索引页中。
B、"分散存放"在主键上"随机"的20个数据页中。
满足C2='XXX'的记录有200000行,索引IDX_C2上每个数据页存放500行索引记录,满足条件数据:
A、"顺序存放"在索引IDX_C2上"连续"的400个索引页中。
B、"分散存放"在主键上"随机"的40000个数据页中。
同时满足C1='XXX' AND C2='XXX'的记录有19行,满足条件数据:
A、"分散存放"在主键上"随机"的19个数据页中 那么:
1、不使用Index Merge Intersect算法需要"顺序读取"1个IDX_C1索引页+"随机读取"20个主键索引数据页
2、使用Index Merge Intersect算法需要"顺序读取"1个IDX_C1索引页+"顺序读取"400个IDX_C2索引页+"随机读取"19个主键索引数据页
针对上面情况,使用Index Merge Intersect算法需要额外读取400个IDX_C2索引页才能降低1次主键的回表查询和随机读取,显然性能更差。

Index Merge Intersect算法和Index condition Pushdown特性

在MySQL官方文档中,Index Merge Intersect算法可以应用在分别使用主键和二级索引的查询中,如:

SELECT *
FROM innodb_table
WHERE primary_key < 10
AND key_col1 = 20;

在未引入ICP特性的早期MySQL版本中,主键上过滤条件(primary_key < 10)不会"下推"到查询满足key_col1 = 20条件的过程中,因此可以使用Index Merge Intersect算法来减少回表查找次数。

在引入ICP特性的MySQL版本中,由于辅助索引的索引记录中都包含主键列数据,因此主键上过滤条件(primary_key < 10)可以"下推"到查询满足key_col1 = 20条件的过程中,无需再使用Index Merge Intersect算法。

## 在MySQL 5.7版本中测试
SELECT *
FROM TB001
WHERE C1=10
AND ID<100;
## 执行计划为:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: TB001
partitions: NULL
type: ref
possible_keys: PRIMARY,IDX_C1
key: IDX_C1
key_len: 5
ref: const
rows: 1
filtered: 33.33
Extra: Using where; Using index
## 执行计划Extra部分没有INDEX MERGE相关信息

Index Merge Intersect性能问题优化

在部分场景中,使用Index Merge Intersec算法会带来严重的性能问题,DBA可以通过MySQL参数optimizer_switch来关闭该特性。

对于通过Index Merge Intersec算法受益的查询,可以考虑使用组合索引或覆盖索引来替换单列索引。

如对上面查询,可以将索引IDX_C1(C1)调整为IDX_C1_C2(C1,C2),其查询性能更佳。

Index Merge Union算法
当查询过滤条件(WHERE部分)上使用OR关联多个不同KEY的过滤条件时,如:

# 表TB1001有主键索引PRIMARY KEY(ID)
# 表TB1001有辅助索引IDX_C1(C1) 和辅助索引IDC_C2(C2)
SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX';

其操作步骤为:

1、使用IDX_C1索引获取到满足条件的[C1,ID]记录,记录默认按照ID排序
2、使用IDX_C1索引获取到满足条件的[C1,ID]记录,记录默认按照ID排序
3、将已经按照ID排序的步骤1和步骤2的数据进行合并去重ID。
4、按照ID回表查找并返回

伪代码为:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
UNION
SELECT ID FROM TB1001 WHERE C2='XXX'
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID 在创建索引IDX_C1(ID)时,其等价为IDX_C1(C1,ID),相同C1值的记录按ID值排序,因此UNION操作的两个中见结果集在ID上时有序的。

Index Merge Sort-Union算法

当查询过滤条件(WHERE部分)上使用OR关联多个不同KEY的过滤条件时,如:

# 表TB1001有主键索引PRIMARY KEY(ID)
# 表TB1001有辅助索引IDX_C1(C1) 和辅助索引IDC_C2(C2)
SELECT * FROM TB1001 WHERE C1>'XXX' OR C2<'XXX';

其操作步骤为:

1、使用IDX_C1索引获取到满足条件的[C1,ID]记录,再按照ID进行排序
2、使用IDX_C1索引获取到满足条件的[C1,ID]记录,再按照ID进行排序
3、将步骤1和步骤2的已按ID排序后数据进行合并去重ID。
4、按照ID回表查找并返回

伪代码为:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1>'XXX'
ORDER BY ID
UNION
SELECT ID FROM TB1001 WHERE C2>'XXX'
ORDER BY ID
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID 在创建索引IDX_C1(ID)时,其等价为IDX_C1(C1,ID),对C1列进行范围查询返回数据的数据按照C1+ID排序,在ID列上是无序的,因此UNION操作前需先对两个中间结果集排序。

Index Merge Union相关优化
在禁用Index Merge特性时,可以通过SQL将OR操作改写为UNION ALL操作,使查询同时使用多个索引。

如上面使用Index Merge Union算法的查询,可以改写为:

#改写前:
SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX'; # 改写后
SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
UNION ALL
SELECT ID FROM TB1001 WHERE C2='XXX' AND (C1<>'XXX' OR C1 IS NULL)
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID

PS: 将IDX_C2(C2)改写为IDX_C2_C2(C1,C2)能在UNION操作前避免回表查询。

MySQL Execute Plan--Index Merge特性的更多相关文章

  1. MySQL 查询优化之 Index Merge

    MySQL 查询优化之 Index Merge Index Merge Intersection 访问算法 Index Merge Union 访问算法 Index Merge Sort-Union ...

  2. MySQL 优化之 index merge(索引合并)

    深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where ...

  3. MySQL index merge

    深入理解 index merge 是使用索引进行优化的重要基础之一. [ index merge]       当where谓词中存在多个条件(或者join)涉及到多个字段,它们之间进行 AND 或者 ...

  4. MySQL Index Merge Optimization

    Index Merge用在通过一些range scans得到检索数据行和合并成一个整体.合并可以通过 unions,intersections,或者unions-intersection运用在底层的扫 ...

  5. MySQL ICP(Index Condition Pushdown)特性

    一.SQL的where条件提取规则 在ICP(Index Condition Pushdown,索引条件下推)特性之前,必须先搞明白根据何登成大神总结出一套放置于所有SQL语句而皆准的where查询条 ...

  6. MySQL中Index Merge简介

    索引合并优化 官网翻译 MySQL5.7文档 索引合并是为了减少几个范围(type中的range类型:range can be used when a key column is compared t ...

  7. 《转》MySQL 5.7版本新特性连载

    MySQL 5.7版本新特性连载(一) 本文将和大家一起分享下5.7的新特性,不过我们要先从即将被删除的特性以及建议不再使用的特性说起.根据这些情况,我们在新版本及以后的版本中,应该不再使用,避免未来 ...

  8. index merge的一次优化

    手机微博4040端口SQL优化 现象 某端口常态化延迟,通过使用pt-query-digest发现主要由于一条count(*)语句引发,具体如下: # .5s .58M rss, .84M vsz # ...

  9. 8.2.1.4 Index Merge Optimization 索引合并优化:

    8.2.1.4 Index Merge Optimization 索引合并优化: 索引合并方法是用于检索记录 使用多个 范围扫描和合并它们的结果集到一起 mysql> show index fr ...

随机推荐

  1. CSS-13-块级元素和行内元素

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. P4452 [国家集训队]航班安排(最大费用最大流)

    P4452 [国家集训队]航班安排 题目传送门 解题思路: 感觉题面让人有很多误解,就是说有k架飞机在0点从0号机场起飞,在t时刻返回机场,给出空载飞行的时间和花费以及m个包机请求的花费和起始时间和终 ...

  3. OpenDJ入门 | 5分钟快速入门Forgerock DS

    本教程为了让大家快速体验,故不做深入讲解,详细内容请留意后续进阶教程 介绍 OpenDJ是一个目录服务器,它实现了各种轻量级目录访问协议和相关标准,包括完全符合LDAPv3,但也支持目录服务标记语言( ...

  4. vuex之state(一)

    我的理解 个人认为,不用说得太过深奥,vuex其实就是把一个应用的某些数据统一管理起来,以便其他的组件更方便的操作该数据. 为什么使用vuex 当项目结构越来越复杂,组件的多层嵌套使得数据传递非常繁琐 ...

  5. 暑假第一周总结(在centos虚拟机上安装jdk以及hadoop并对hadoop进行配置)

    本周主要就是对虚拟机进行安装并在上边安装jdk以及hadoop并对其进行配置. 在看林子雨老师的教程时,下载了老师所给的全套的下载软件,在安装时发现老师所给的VirtualBox安装后无法正常启动,尝 ...

  6. DOCKER 学习笔记5 Springboot+nginx+mysql 容器编排

    前言 在上节的内容中,我们已经通过一个简单的实例,将Docker-compose 进行了实际的应用.这一小节中.我们将通过学习和了解,着重认识容器的编排,上一节只算是一个小小的测试.在这一节中.我们将 ...

  7. 1-NoSQL介绍及Redis安装

    背景 随着互联网的不断发展和软件架构的不断复杂化,同时随着网站访问量的日渐上升,导致传统单机关系型数据库应用已经无法满足人们的需求,在高并发的场景下,频繁的数据库存取操作使得服务器压力剧增,甚至导致服 ...

  8. 浅谈构建前端自动化工作流程一 之 nvm

    1.NVM简介 我们可能同时在进行2个项目,而2个不同的项目所使用的node版本又是不一样的,或者是要用更新的node版本进行试验和学习.这种情况下,对于维护多个版本的node将会是一件非常麻烦的事情 ...

  9. 【转载】计算机程序的思维逻辑 (8) - char的真正含义

    看似简单的char 通过前两节,我们应该对字符和文本的编码和乱码有了一个清晰的认识,但前两节都是与编程语言无关的,我们还是不知道怎么在程序中处理字符和文本. 本节讨论在Java中进行字符处理的基础 - ...

  10. POJ_1222_高斯消元

    题目描述: 每组数据给出一个5*6的0 1矩阵,每次操作可以把某个位置及其四周的位置0 1置换,要求输出操作位置的矩阵. 思路: 每个位置操作2次则等于没有操作,所以每个位置有操作和不操作两种选择,爆 ...