索引合并,能不用就不要用吧!

news2024/10/7 6:37:59

文章目录

    • 1. 问题重现
    • 2. 索引合并
      • 2.1 Using intersect(...)
      • 2.2 Using union(...)
      • 2.3 Using sort_union(...)
      • 2.4 索引合并原理
    • 3. 索引合并的问题

在前面的文章中,松哥和小伙伴们分享了 MySQL 中,InnoDB 存储引擎的数据结构,小伙伴们知道,当我们使用索引进行搜索的时候,每一次的搜索都是在某一棵 B+Tree 中搜索的,如果使用了二级索引的话,可能还会涉及到回表。

那么现在问题来了,如果我们的搜索条件中包含两个字段,且这两个字段都有独立的索引,那么 MySQL 会怎么处理?今天我们就来讨论下这个话题。

1. 问题重现

为了方便小伙伴们理解,我先通过 SQL 来把我的问题重复一下。

我使用的测试数据是 MySQL 官网提供的测试数据,相关的介绍文档在:

  • https://dev.mysql.com/doc/employee/en/

相应的数据库脚本在:

  • https://github.com/datacharmer/test_db

小伙伴们可以自行下载这个数据库脚本并导入到自己的数据库之中。

在官方提供的案例中,有一个这样的表:

CREATE TABLE `film_actor` (
  `actor_id` smallint unsigned NOT NULL,
  `film_id` smallint unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`,`film_id`),
  KEY `idx_fk_film_id` (`film_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

在这个表中有两个索引,其中一个是主键索引,主键索引是一个联合索引,还有一个是根据 film_id 建立的普通索引。现在假设我有如下 SQL 需要执行:

select * from film_actor where film_id=1 or actor_id=1;

那么问题来了,这个查询会用到索引吗?

想知道有没有用到索引,用 explain 关键字看一下就知道了:

explain select * from film_actor where film_id=1 or actor_id=1;

执行结果如下:

小伙伴们看到,此时 typeindex_mergepossible_keyskey 中,都给出来了两个索引,Extra 中的值为 Using union(idx_fk_film_id,PRIMARY); Using where

看起来是用了索引,但是具体是怎么用的,这个执行计划该如何解读呢?

这个其实就是一个索引合并,接下来我们就来看下到底什么是索引合并。

2. 索引合并

index_merge 表示索引合并,当同一个表中的搜索条件中同时存在多个索引的时候,MySQL 会分别对这些索引进行扫描,然后将扫描结果进行合并,合并分三种情况:

  1. 对各自扫描结果求并集(unions)。
  2. 对各自扫描结果求交集(intersections)。
  3. 前两者的组合。

在官方文档中给了四个可能会用到索引合并的例子:

SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;

SELECT * FROM tbl_name
  WHERE (key1 = 10 OR key2 = 20) AND non_key = 30;

SELECT * FROM t1, t2
  WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%')
  AND t2.key1 = t1.some_col;

SELECT * FROM t1, t2
  WHERE t1.key1 = 1
  AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2);

有的时候,我们写的 SQL,明明可以合并,但是系统却没有合并,此时我们对查询条件做一些调整,例如:

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

另外需要注意的是,索引合并不适用于全文索引。

在 explain 执行计划中,如果用到了索引合并,Extra 字段的值一般分为三种情况,分别是:

  • Using intersect(…)
  • Using union(…)
  • Using sort_union(…)

上文案例属于第二种情况。

那么接下来把这三种情况都来和小伙伴们聊一下。

2.1 Using intersect(…)

这个就是对多个扫描结果求交集。

并不是只要涉及到多个索引,且是 AND,就会触发 Using intersect,有两个条件:

  1. 如果是二级索引,则必须是等值查询。如果二级索引是复合索引,则复合索引的每一列都必须覆盖到,不能只是其中的某几列。
  2. 主键索引可以是范围查询。

我们来看官方给出的一个例子,如下:

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

key_part1 - key_partN 就是复合索引中的所有列(必须是所有列)。

对于第 2 点,如果涉及到主键索引,则主键索引可以是范围查询,例如下面这样(但是二级索引依然只能是等值查询):

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;

key1_part1key1_part2 分别表示同一个复合索引的第一列和第二列(一共就两列),此时和 key2 一起作为查询条件,也有可能会用到索引合并。

上面这些情况都是在各自搜索完成之后求交集。

举一个简单的例子吧,还是 MySQL 官方的测试数据,sakila 库中有一个 actor 表,该表结构如下:

CREATE TABLE `actor` (
  `actor_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) NOT NULL,
  `last_name` varchar(45) NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`),
  KEY `idx_actor_last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb3;

可以看到,有一个主键,有一个普通索引,我执行如下 SQL:

select * from actor where actor_id<10 and last_name='WAHLBERG'

执行计划如下:

可以看到,用到了索引合并,且是 Using intersect

2.2 Using union(…)

求并集的跟求交集的比较像,就是 AND 变成了 OR。

当二级索引是等值查询,或者是组合索引,但是要求组合索引的每一列都必须覆盖到,不能只是覆盖到部分列,例如下面这个查询条件:

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

key_part1~key_partN 就是同一个复合索引的不同列,同时在该复合索引中,也一共就只有这 N 个字段,这种情况就会用到 Using union

InnoBD 表上的主键范围查询也有可能会触发 Using union

符合 2.1 小节的情况,将 AND 换成 OR 之后,也有可能会触发 Using union

这个例子就不用举了,文章一开始的就是。

2.3 Using sort_union(…)

很明显,2.2 小节的条件比较苛刻,二级索引必须是等值查询才能触发 Using union,而我们日常使用的时候,范围查询也是非常常见的,所以又有了 Using sort_union,这个的要求就宽松一些了:

  • 二级索引也可以按照范围匹配
  • 复合索引也不用覆盖所有列

举个例子,如下面的 SQL:

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;

二级索引范围搜索,也有可能触发 Using sort_union 的。

2.4 索引合并原理

在 2.1 小节和 2.2 小节,分别是求交集和求并集,为了 intersect 和 union 操作方便,在各个单独的索引扫描的时候,都是要获取到有序的主键值的合集,各个索引都获取到有序的主键,然后求交集或者并集就会比较方便。

因此,在 2.1 和 2.2 小节,都是主键索引可以范围搜索,因为主键索引本身主键就是有序的;二级索引则有诸多限制,这诸多限制的最终目的都是为了做到最终拿到的主键值是有序的。

例如:

  • 二级索引必须等值匹配,等值匹配意味着最终拿到的 B+Tree 的叶子上的主键值就是唯一的;二级索引如果可以按照范围查找,那么最终从二级索引的 B+Tree 的叶子结点上拿到的主键值就不是有序的了。
  • 类似的,复合索引必须覆盖到所有列也是相似的原因,因为如果没有覆盖到所有列,意味着最终拿到的主键值也是无序的。

2.3 小节允许二级索引按照范围搜索,这是因为在 Using sort_union 中,会先对拿到的主键值进行排序,然后才会去求交集或者并集,当然,相比于 2.1 和 2.2 小节,2.3 小节的性能也会降低一些。

3. 索引合并的问题

索引合并看着似乎提升了 MySQL 搜索的性能,然而,一般出现索引合并,大概率都是因为索引创建的不合理,我们需要重新审视自己的索引。

如上面 2.3 小节所述,这种方式在查询的过程中需要缓存临时数据、需要排序然后才能求交集或者并集,这些操作都会消耗掉大部分的 CPU 和内存资源。并且这些消耗不会被计算到查询成本中,因为 MySQL 优化器只关心随机页面的读取问题,并不会关心这里涉及到的这些额外计算问题,所以,在一些极端情况下,索引合并的性能可能还不如全表扫描。

因此,有时候如果我们确定自己不需要索引合并,那么可以通过 ignore index 来忽略掉一些索引,如下(对比 2.1 小节截图):

也可以通过 optimizer_switch 来关闭索引合并功能,如下:

好啦,索引合并就和小伙伴们聊这么多吧~感兴趣的小伙伴也可以尝试下哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTB-OpenKeyS

HTB-OpenKeyS 信息收集80端口立足于JenniferJennifer -> root 信息收集 80端口 对其进行简单的SQL注入测试和NoSQL注入测试后进行目录扫描。 auth.swp文件内容如下&#xff1a; 代码不是很完整&#xff0c;只能大致了解意思&#xff08;请原谅我脑子抽了没注意是个swp交换…

USB 连接检测

文章目录 连接检测连接状态的检测带 Vbus 检测功能的 USB 设备不带 Vbus 检测功能的 USB 设备 连接前的初始化设备端主机端 建立连接过程手册规定检测时间及电平标准 连接检测 USB 协议支持热插拔的特性决定了 USB 主机必须能够动态地检测 USB 设备的连接和断开&#xff0c;这…

linux【网络编程】之网络基础

linux【网络编程】之网络基础 一、网络协议与协议分层1.1 为什么要分层1.2 OSI七层模型1.3 TCP/IP五层(或四层)模型 二、网络传输流程2.1 了解局域网2.2 同一网段内的两台主机进行文件传输2.3 跨网段的主机的文件传输 三、数据包封装和分用四、网络中的地址管理4.1 IP地址4.2 M…

【Simulink】0基础入门教程 P1 搭建自己的第一个模型 实现加减乘除四则运算

目录 工作路径的设置&#xff1a; Simulink的两种打开方式 模块的基本操作 建立一个新的空白模型&#xff0c;创建模型 加减乘除模块的名称 模块之间连线的两种方法 显示模块 Display 搭建子系统subsystem 将加法模块Add更改为多输入模块 本文记录Simulink学习&#x…

[零刻]EQ12EQ12Pro调整风扇转速教程

调整 CPU 风扇转速可以有不同的用途&#xff0c;具体取决于您的计算机和使用情况。 降低噪音&#xff1a;如果您的风扇的噪音很大&#xff0c;可以通过降低 CPU 风扇的转速来减少噪音。这可以通过在 BIOS 或中设置 CPU 风扇转速控制来实现。 提高性能&#xff1a;如果您的计算…

OpenVINO 2022.3实战一:Window 10 环境下用 OpenVINO 2022.3部署yolov5 7.0

Window 10 环境下用 OpenVINO 2022.3部署yolov5_7.0 1 下载并解压 OpenVINO Runtime OpenVINO™ Runtime 2022.3 以压缩包 (OpenVINO Archives) 的形式提供。 下载地址&#xff1a; storage.openvinotoolkit.org 下载后解压到 C:\Intel\openvino_2022.3.0 配置环境&#xff…

5月5日 8H25min|5月6日 3H10min|时间轴复盘

7:30-8:00 起床洗漱吃饭 8:00-8:30 背书 【30min】 8:30-9:40 对话单词 【1h10min】 9:45-11:30 听力精听 【2h-15min】 11:30-12:10 吃午饭吃水果 12:10-12:50 继续吃饭之前没完成的 【40min】 13:00-14:30 健身 14:35-14:43 语法 【1…

asdfghasdfghjkl

PDL1检测&#xff1a; 肿瘤细胞高表达PD-L1分子&#xff0c;与肿瘤部位浸润T淋巴细胞表面的PD-1分子结合后&#xff0c;抑制T细胞活性&#xff0c;实现肿瘤的免疫逃避。而目前PD-1/PD-L1抑制剂均是检测PD-L1的表达。 目前在NSCLC治疗中&#xff0c;对于每个PD-1/PD-L1抑制剂&a…

【Hive大数据】Hive分区表与分桶表使用详解

目录 一、分区概念产生背景 二、分区表特点 三、分区表类型 3.1 单分区 3.2 多分区 四、动态分区与静态分区 4.1 静态分区【静态加载】 4.1.1 操作演示 4.2 多重分区 4.2.1 操作演示 4.3 分区数据动态加载 4.3.1 分区表数据加载 -- 动态分区 4.3.2 操作演示 五、…

mysql事务及搜索引擎

mysql事务后半部分 加快查询速度索引会自动排序&#xff0c;&#xff08;升序&#xff09; select * from t1&#xff1b;全盘扫描 where可以索引查找show create table 索引是一个排序的列表&#xff0c;包含字段值和相应行数据的物理地址 事务是一种机制&#xff0c;一个…

Misc小总结

Misc分类 个人认为Misc中的题目可分为七大类&#xff0c;图片隐写&#xff0c;音视频隐写&#xff0c;其它隐写(PPT、word文档等隐写)&#xff0c;压缩包破解&#xff0c;流量分析&#xff0c;取证&#xff0c;编码或密码。这里面涉及的知识点当然是很多的&#xff0c;有很多你…

大学毕业设计使用python制作

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

Python标准数据类型-字符串常用方法(上)【文末送书】

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1 &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;零基础入门篇 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一座的高山…

经验总结:(Redis NoSQL数据库快速入门)

一、Nosql概述 为什么使用Nosql 1、单机Mysql时代 90年代,一个网站的访问量一般不会太大&#xff0c;单个数据库完全够用。随着用户增多&#xff0c;网站出现以下问题 数据量增加到一定程度&#xff0c;单机数据库就放不下了数据的索引&#xff08;B Tree&#xff09;,一个机…

【Linux】进程的终止,等待(不包含进程的程序替换)

信号的部分会在后面仔细讲&#xff0c;本文不涉及 目录 1.进程终止以及退出码的理解 2.进程退出 3.进程等待 1.进程终止以及退出码的理解 1.情况分类 &#xff08;1&#xff09;正常执行完 a.结果正确 b.结果不正确 反思为什么&#xff1f; &#xff08;2&#xff…

CesiumForUnreal去掉左下角的Ion Logo

文章目录 1.实现目标2.实现过程3.参考资料1.实现目标 记录一下使用CesiumForUnreal插件过程中如何清除左下角的Cesium Ion Logo,清除前后的对比截图如下所示。 原始样式去除后2.实现过程 记录一下实现的过程(含踩坑记录,可能有一点啰嗦)。 (1)首先看一下是哪个蓝图添加的…

【STM32CubeMX】F103窗口看门狗

前言 本文记录了我学习STM32CubeMX的过程&#xff0c;方便以后回忆。我们使用的开发板是基于STM32F103C6T6的。本章记录了窗口看门狗的使用配置。要学习的话&#xff0c;注意流程一说&#xff0c;省略的内容。 基础 窗口看门狗(WWDG)属于APB1上外设。窗口看门狗(WWDG)的时钟源…

【小结】git合并分支总结

首先理清以下几个关系&#xff1a; 1、git有本地库和远程库。 ①本地仓库&#xff1a;也就是电脑上存储的代码&#xff0c;本地代码&#xff0c;一般在某个盘中。 ②远程仓库&#xff1a;是云上的库&#xff0c;比如gitee,github等等。 2、分支&#xff1a;分为本地分支和远…

手机摄影(三)

第七章 构图&#xff0c;用光与色彩 构图的原则&#xff1a; 画面简洁 突出主体 陪体和主体&#xff1a;如果没有枯叶做前景&#xff0c;画面的空间感和深秋氛围会大打折扣。 看到一张你认为很美的照片时&#xff0c;要问自己几个问题&#xff1a; • 这张照片的主体是什么…

jvm之启动参数

写在前面 本文一起看下jvm启动参数相关内容&#xff0c;通过本文希望我自己也希望大家能够真正的应用到实际的工作中。 1&#xff1a;基本内容介绍 一般我们启动java程序有两种方式&#xff0c;一种是直接运行一个有main函数的class&#xff0c;第二种是运行一个在MANIFEST文…