MySQL查询性能优化之索引覆盖、索引下推、索引潜水、索引合并

索引覆盖

什么是索引覆盖

select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。

如何实现索引覆盖?

最常见的方法就是:将被查询的字段,建立到联合索引(如果只有一个字段,普通索引也可以)里去。

例如建立如下表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `surname` varchar(2) NOT NULL DEFAULT '' COMMENT '姓',
  `name` varchar(10) NOT NULL DEFAULT '' COMMENT '名',
  `full_name` varchar(12) GENERATED ALWAYS AS (concat(`surname`,`name`)) STORED COMMENT '全名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(2) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_age_sex` (`age`,`sex`)
) ENGINE=InnoDB AUTO_INCREMENT=1144780 DEFAULT CHARSET=utf8mb4

在这里插入图片描述
当查询所有字段时,需要使用了索引,但是还需要回表获取所有的行数据。
在这里插入图片描述
当查询只有age、sex时,explain 的Extra为Using index表示使用了索引覆盖。

索引下推

什么是所有下推?

索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6版本的新特性,它能减少回表查询次数,提高查询效率。

索引下推有哪些作用?

主要作用有两个:

  1. 减少回表查询的次数
  2. 减少存储引擎和MySQL Server层的数据传输量

索引下推配置

查看索引下推的配置:

show variables like '%optimizer_switch%';

如果输出结果中,显示 index_condition_pushdown=on,表示开启了索引下推。
在这里插入图片描述

开启索引下推

开启索引下推:

set optimizer_switch="index_condition_pushdown=on";
关闭索引下推

关闭索引下推:

set optimizer_switch="index_condition_pushdown=off";

索引下推原理

创建实战数据表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `surname` varchar(2) NOT NULL DEFAULT '' COMMENT '姓',
  `name` varchar(10) NOT NULL DEFAULT '' COMMENT '名',
  `full_name` varchar(12) GENERATED ALWAYS AS (concat(`surname`,`name`)) STORED COMMENT '全名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(2) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_age_sex` (`age`,`sex`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4

在age、sex列上建立联合索引。

在没有使用索引下推的情况,查询过程是这样的:

  1. 存储引擎根据where条件中age索引字段,找到符合条件行主键ID
  2. 然后二次回表查询,根据主键ID去主键索引上找到整行记录
  3. 把数据返回给MySQL Server层,再根据where中sex条件,筛选出符合要求的一行记录
  4. 返回给客户端

在使用索引下推的情况,查询过程是这样的:

  1. 存储引擎根据where条件中age索引字段,找到符合条件的行记录,再用sex条件筛选出符合条件主键ID
  2. 然后二次回表查询,根据主键ID去主键索引上找到该整行记录
  3. 把数据返回给MySQL Server层
  4. 返回给客户端
    在这里插入图片描述
    执行计划中的Extra列显示了Using index condition,表示用到了索引下推的优化逻辑。

索引下推应用范围

  1. 适用于InnoDB 引擎和 MyISAM 引擎的查询
  2. 适用于执行计划是range, ref, eq_ref, ref_or_null的范围查询
  3. 对于InnoDB表,仅用于非聚簇索引。索引下推的目标是减少全行读取次数,从而减少 I/O 操作。对于 InnoDB聚集索引,完整的记录已经读入InnoDB 缓冲区。在这种情况下使用索引下推 不会减少 I/O。
  4. 子查询不能使用索引下推
  5. 存储过程不能使用索引下推

索引潜水

什么是索引潜水?

先看下实际操作。
创建表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `surname` varchar(2) NOT NULL DEFAULT '' COMMENT '姓',
  `name` varchar(10) NOT NULL DEFAULT '' COMMENT '名',
  `full_name` varchar(12) GENERATED ALWAYS AS (concat(`surname`,`name`)) STORED COMMENT '全名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(2) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_age_sex` (`age`,`sex`)
) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8mb4

往里面写入128行数据:

select count(id) from user;

在这里插入图片描述
执行in操作:
在这里插入图片描述
在这里插入图片描述
同样是in的查询,参数数量不一样时,rows和type都不一样。

in参数数量决定了走索引潜水还是索引统计的方式。

索引潜水有哪些作用?

都用索引潜水(Index dive)的方式预估扫描行数,不好吗?

其实这是基于成本的考虑索引潜水估算成本较高,适合小数据量。索引统计估算成本较低,适合大数据量。

一般情况下,我们的where语句的in条件的参数不会太多,适合使用索引潜水预估扫描行数。

建议还在使用MySQL5.7.3之前版本的同学们,手动修改一下索引潜水的配置参数,改成合适的数值。

索引潜水配置

查询配置:

show variables like '%eq_range_index_dive_limit%';

在这里插入图片描述
eq_range_index_dive_limit 配置的作用就是:
当where语句in条件中参数个数小于这个值的时候,MySQL就采用索引潜水(Index dive)的方式预估扫描行数,非常准确。

当where语句in条件中参数个数大于等于这个值的时候,MySQL就采用另一种方式索引统计(Index statistics)预估扫描行数,误差较大。

修改配置:

set eq_range_index_dive_limit=200;

索引合并

什么是索引合并?

当单表存在多个索引,一个SQL语句的where中又含有多个索引字段,在执行SQL语句时每个索引都可能返回一个结果集,MySQL会将其求交集或者并集,或者是交集和并集的组合。也就是说一次查询中可以使用多个索引。

我们创建一个表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `surname` varchar(2) NOT NULL DEFAULT '' COMMENT '姓',
  `name` varchar(10) NOT NULL DEFAULT '' COMMENT '名',
  `full_name` varchar(12) GENERATED ALWAYS AS (concat(`surname`,`name`)) STORED COMMENT '全名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `sex` varchar(2) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_age_sex` (`age`,`sex`)
) ENGINE=InnoDB AUTO_INCREMENT=151 DEFAULT CHARSET=utf8mb4

在age、sex列建立联合索引,在name建立索引。

执行查询时:
在这里插入图片描述
在使用explain 时,在type那一列会显示index_merge,key那一列是所有使用到的索引。

索引合并又包含三个算法,在explain中显示:

  1. using intersect
    index merge intersection access algorithm(索引合并交集访问算法)。
    对于每一个使用到的索引进行查询,查询主键值集合,然后进行合并,求交集,也就是AND运算。

  2. using union
    index merge union access algorithm(索引合并并集访问算法)
    容易看出,与上述的算法类似,不过是使用了or连接条件,求并集。
    执行流程与index merge intersect 类似,依旧是查询了有序的主键集合,然后进行求并集。

  3. using sort_union
    index merge sort sort-union access algorithm (索引合并排序并集访问算法)
    根据索引查询得到主键集合,对于每个主键集合进行排序,然后求并集。

索引合并有哪些作用?

索引合并能使用多个索引,提高查询的速度。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冲上云霄的Jayden

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值