MySQL的3种索引合并优化⭐️or到底能不能用索引?

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: MySQL的3种索引合并优化⭐️or到底能不能用索引?

前言

前文我们讨论过MySQL优化回表的多种方式:索引条件下推ICP、多范围读取MRR、覆盖索引等

这篇文章我们来聊聊MySQL提供的另一种优化回表的手段:index merge 索引合并

在阅读本文前,你需要了解MySQL的server层与存储引擎层如何交互、二级索引和聚簇索引的区别、回表等知识

如果同学不太了解这些知识可以回看前文:

MySQL的优化利器⭐️索引条件下推,千万数据下性能提升273%🚀

MySQL的优化利器⭐️Multi Range Read与Covering Index是如何优化回表的?

MySQL导致索引失效的八股文中有这样一条:使用or会导致索引失效

那么是不是所有场景都会失效呢?带着这个问题,我们往下看

案例使用上篇文章的座位表,并分别建立seat_code、student_id 两个二级索引

CREATE TABLE `seat` (
  `seat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '座位ID',
  `seat_code` char(10) DEFAULT NULL COMMENT '座位码',
  `student_id` bigint(20) DEFAULT NULL COMMENT '座位关联的学生ID',
  PRIMARY KEY (`seat_id`),
  KEY `idx_student_id` (`student_id`),
  KEY `idx_seat_code` (`seat_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

index merge

正常情况下优化器只能选择一个它认为最成本最低的索引来生成执行计划

但在某些情况下可以使用多个索引进行索引合来优化

索引合并的优化分成三种方式:

  1. index merge intersection 交集索引合并
  2. index merge union 并集索引合并
  3. index merge sort union 排序并集索引合并

三种方式各自有什么不同呢?请按顺序往下看:

index merge intersection

index merge intersection 是用于交集的索引合并,交集往往和查询条件中的and相关

什么是交集?

比如有两个集合分别是(1,2,3)、(2,3,4),那么交集就是它们都存在的值(2,3)

举例这样一条SQL:

select * from seat 
where seat_code = 'caicaiseat' and student_id = 1

当不使用索引合并优化时,优化器可能选择seat_code索引或者student_id索引

当使用seat_code索引时,先在索引中找到满足seat_code  = caicaiseat的记录,再回表查询聚簇索引获取完整记录

image.png

关闭交集索引合并的优化

SET optimizer_switch='index_merge_intersection=off';

查看执行计划

image.png

在这种场景下,可能存在很多满足seat_code  = caicaiseat ,但是不满足 student_id = 1的记录

如果这些记录也需要回表,再回表后还是会被过滤,浪费资源来对这些记录进行回表

回表查询不仅仅是多查询一次,在这次查询中还可能是随机IO,查询量大的情况下,回表的代价是很高的

使用交集索引合并后

  1. 先使用seat_code索引找到满足 seat_code  = caicaiseat 的条件
  2. 然后使用student_id索引找到满足 student_id = 1 的条件
  3. 接着根据主键seat_id对它们进行交集过滤,剩下的记录再进行回表,以此来减少回表的次数

(图中未回表是因为正好满足覆盖索引)

image.png

需要注意的是使用交集索引合并需要主键值需要有序,如果主键值乱序进行交集过滤,在回表时会产生随机IO,得不偿失

在二级索引中只有索引列相等时才对主键值进行排序,因此大部分使用交集索引合并的场景是等值比较=

开启交集索引合并,查看执行计划

type类型为索引合并,使用到这两个索引,附加信息显示用到交集索引合并,并且还用上覆盖索引不需要回表

由于seat座位表只存在主键seat_id、座位码seat_code、学生ID student_id,需要查询的列都在二级索引上,因此不用回表

image.png

有的同学可能注意到:为啥不把seat_code与student_id组成(seat_code,student_id)联合索引呢?

实际上(seat_code,student_id)联合索引也是可以用上索引的,但如果要单独查询student_id就会导致索引失效了

index merge union

index merge union是用于并集的索引合并,并集往往与查询条件or相关

什么是并集?

比如有两个集合分别是(1,2,3)、(2,3,4),那么并集就是它们都存在值的总和(1,2,3,4)

举例这样一条SQL

select * from seat 
where seat_code = 'caicaiseat' or student_id = 1;

当不使用index merge union的情况下,会直接全表扫描(聚簇索引),依次判断记录是否满足条件

index_merge_union=off 关闭并集索引合并

index_merge_sort_union 关闭排序的并集索引合并(是下一个要说明的索引合并,其在并集索引合并的基础上增加排序)

image.png

当使用index merge union的情况下

  1. 先使用seat_code索引找到满足条件seat_code = 'caicaiseat'的记录
  2. 再使用student_id索引找到满足条件student_id = 1的记录
  3. 然后将它们的主键值seat_id取并集后再回表查询,以此来减少开销

image.png

开启union优化,查看执行计划:已经使用index merge union

image.png

所以以后不要再傻乎乎的背八股文说or用不上索引啦~

使用index merge union的前提与index merge intersection类似也需要主键值有序

index merge sort union

由于or在某些场景下会让优化器认为回表成本大,不如全表扫描,从而导致索引失效

而index merge union的使用前提(主键有序)太苛刻,很多场景下还是无法使用索引

index merge sort union 排序的并集索引合并:对主键值无序的场景排序后再进行并集

比如这条SQL中

select * from seat where seat_code like 'a%' and student_id = 1

查询条件seat_code不再是等值比较,这样满足seat_code like 'a%'记录的主键值也不一定是有序的

而seat_code索引中满足 student_id = 1的记录主键值是有序的

为了将seat_code索引满足条件的记录与seat_code索引满足条件的记录作并集

先对seat_code索引满足条件的记录进行排序,有序后再取并集

image.png

开启sort union后,查看执行计划:使用index merge sort union

image.png

情况与index merge union类似,使用前提可以是主键乱序,在主键乱序后对其进行排序再取交集

总结

index merge索引合并优化默认开启,分为intersection交集、union并集、sort union排序并集三种方式

index merge intersection使用的前提:and和可以使用多个索引且结果中主键有序,分别在对应的索引中找到满足条件的记录,对记录进行交集过滤后再进行回表,减少不必要的回表开销

index merge union 使用的前提:or和可以使用多个索引且结果中主键有序,分别在对应索引中找到满足条件的记录,对记录进行并集过滤后再进行回表,避免全表扫描

index merge intersection/union使用的前提都是需要主键有序,因为主键乱序需要先排序再进行交集/并集,否则会有随机IO

由于index merge union中or容易导致优化器认为回表成本大进而全表扫描,而满足主键有序的场景太苛刻,因此使用index merge sort union 在主键乱序的情况下排序再取并集

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 由点到线,由线到面,构建MySQL知识体系,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 gitee-StudyJavagithub-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
21天前
|
存储 自然语言处理 关系型数据库
MySQL高级篇——索引的创建与设计原则
索引的分类与使用、MySQL8.0索引新特性、适合创建索引的情况、不适合创建索引的情况
MySQL高级篇——索引的创建与设计原则
|
21天前
|
存储 SQL 关系型数据库
MySQL高级篇——索引失效的11种情况
索引优化思路、要尽量满足全值匹配、最佳左前缀法则、主键插入顺序尽量自增、计算、函数导致索引失效、类型转换(手动或自动)导致索引失效、范围条件右边的列索引失效、不等于符号导致索引失效、is not null、not like无法使用索引、左模糊查询导致索引失效、“OR”前后存在非索引列,导致索引失效、不同字符集导致索引失败,建议utf8mb4
MySQL高级篇——索引失效的11种情况
|
1月前
|
存储 关系型数据库 MySQL
MySQL基础:索引
MySQL中的索引是一种数据结构,能大幅提升数据库查询效率和减少I/O成本,类似于书的目录帮助快速定位内容。其优势包括提高检索效率和降低排序成本,但会占用空间并影响更新表的效率。鉴于查询远多于更新,索引仍被推荐使用。索引分为多种类型,如B+树和哈希索引,其中B+树因其较低的高度和稳定的查询开销成为常用选择。创建和删除索引需谨慎,以免影响性能。
42 4
MySQL基础:索引
|
21天前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
168 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
21天前
|
SQL 缓存 关系型数据库
MySQL高级篇——关联查询和子查询优化
左外连接:优先右表创建索引,连接字段类型要一致、内连接:驱动表由数据量和索引决定、 join语句原理、子查询优化:拆开查询或优化成连接查询
MySQL高级篇——关联查询和子查询优化
|
21天前
|
存储 缓存 关系型数据库
MySQL高级篇——存储引擎和索引
MyISAM:不支持外键和事务,表锁不适合高并发,只缓存索引,内存要求低,查询快MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不支持事务、行级锁、外键,有一个毫无疑问的缺陷就是崩溃后无法安全恢复。5.5之前默认的存储引擎优势是访问的速度快,对事务完整性没有要求或者以SELECT、INSERT为主的应用针对数据统计有额外的常数存储。故而 count(*) 的查询效率很高表名.frm 存储表结构;表名.MYD 存储数据 (MYData);
MySQL高级篇——存储引擎和索引
|
21天前
|
算法 关系型数据库 MySQL
MySQL高级篇——排序、分组、分页优化
排序优化建议、案例验证、范围查询时索引字段选择、filesort调优、双路排序和单路排序、分组优化、带排序的深分页优化
MySQL高级篇——排序、分组、分页优化
|
21天前
|
存储 关系型数据库 MySQL
MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计
覆盖索引、前缀索引、索引下推、SQL优化、EXISTS 和 IN 的区分、建议COUNT(*)或COUNT(1)、建议SELECT(字段)而不是SELECT(*)、LIMIT 1 对优化的影响、多使用COMMIT、主键设计、自增主键的缺点、淘宝订单号的主键设计、MySQL 8.0改造UUID为有序
MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计
|
5天前
|
存储 关系型数据库 MySQL
MySQL索引失效及避免策略:优化查询性能的关键
MySQL索引失效及避免策略:优化查询性能的关键
22 3
|
10天前
|
关系型数据库 MySQL 数据库
MySQL删除全局唯一索引unique
这篇文章介绍了如何在MySQL数据库中删除全局唯一的索引(unique index),包括查看索引、删除索引的方法和确认删除后的状态。
32 9
下一篇
无影云桌面