导读:

  首先创建一张 test 表,并插入一些数据:

CREATE TABLE `test` (

  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',

  `a` int(11) NOT NULL,

  `b` int(11) NOT NULL,

  `c` int(11) NOT NULL,

  `d` int(11) NOT NULL,

  PRIMARY KEY (`id`),

  KEY `idx_abc` (`a`,`b`,`c`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  其中,test 表中有一个联合索引 idx_abc,其包含索引(a)、索引(ab)、索引(abc)。而我们都知道联合索引在使用时需要遵循最左匹配原则,也就是说,在执行 select * from test where a = 1 and b = 2 and c = 3 使用 索引(abc)、select * from test where a = 1 and b = 2 索引(ab),虽然使用到的索引列不同,但是归根结底都使用的是 idx_abc 索引。

  但是在执行 select * from test where a = 1 and b > 2 and c = 3 时,使用到的索引列仅仅为(ab),但是查询条件中不是三个索引列都存在吗,为什么只用到了两个索引列呢?这个便是我们今天要讨论的问题,即联合索引中,为什么前一个索引列使用了范围查询后,下一个索引列将无法使用索引进行匹配?

一、最左匹配原则使用示例:

1、全值匹配查询时

例如:

select * from test where a = 1 and b = 2 and c = 3;

select * fom test where b = 2 and a = 1 and c = 3;

select * from test where c = 3 and b = 2 and a = 1;

这些查询都能用到索引 idx_abc,因为 MySQL 中有查询优化器,会自动优化查询顺序,所以查询条件中将索引列顺序调换不影响联合索引的使用。

2、匹配左边的列时

例如:

select * from test where a = '1';

select * from test where a = '1' and b = '2';

select * from test where a = '1' and b = '2' and c = '3'

这些查询都从最左边开始连续匹配,用到了索引。

但如果查询条件没有从最左边开始,则不会使用联合索引,查询会转为全表扫描:

select * from test where b = '2';

select * from test where c = '3';

select * from test where b = '1' and c = '3'

这些没有从最左边开始,最后查询没有用到索引,用的是全表扫描。

select * from test where a = 1 and c = 3

部分索引,只有 a 列用到了索引,c 列无法使用索引。

3、匹配列前缀(%)

对于字符型字段的匹配:

  • 如果查询条件是前缀匹配(例如 a like 'As%'),可以使用索引,因为前缀是有序的。
  • 如果查询条件是后缀或中缀匹配(例如 a like '%As' 或 a like '%As%'),则不能使用索引,需要全表扫描。

例:

  • select * from test where a like 'As%'(前缀匹配,走索引查询)
  • select * from test where a like '%As'(全表查询)
  • select * from test where a like '%As%'(全表查询)

4、匹配范围值

例:

  • select * from test where a > 1 and a < 3:一个列进行范围查询,前缀匹配,走索引查询。
  • select * from test where a > 1 and a < 3 and b > 1:多个列同时进行范围查找时。只有对索引最左边的列进行范围查找才用到 B+ 树索引。因此,只有 a 列用到了索引,b 列无法使用索引,查询会基于 1 < a < 3 的范围查找记录后,继续逐条过滤。

5、精确匹配某一列并范围匹配另外一列

例:

  • select * from test where a = 1 and b > 3

在这种查询中,如果左边的列是精确查找,右边的列可以进行范围查找,可以进行范围查找,联合索引会加速查询。

6、精确匹配某一列并范围匹配另外一列,再精确或范围匹配另外一列

例:

  • select * from test where a = 1 and b > 3 and c = 2

在这种查询中,联合索引使用到的索引列仍然只有(a,b)。

解释:

  MySQL 中的索引结构是 B+ 树,叶子节点中的数据是以索引列从小到大的顺序组织起来的,对于联合索引来说,因为索引列不止有一列,所以数据的排列排列先按 a 列进行从小到大的排序,再按 b 列进行排序,最后按 c 列进行排序,对于上述 test 表中的数据,索引列 idx_abc 的叶子节点数据排序可以简化为:

a

b

c

1

2

4

1

2

8

1

6

2

1

6

3

2

2

7

2

7

4

3

2

4

3

2

6

3

3

2

3

3

8

  可以看出,a 是有序的(构建一颗 B+ 树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建 B+ 树。),而 b,c 都是无序的。但是当 a 相同时,b 是有序的;当 b 相同时,c 又是有序的。

  通过对联合索引的结构的了解,那么就可以很好的了解为什么最左匹配原则中如果遇到范围查询就会停止了。以 select * from test where a=5 and b > 0 and c =1 为例,当查询到 b 的值以后(这是一个范围值),c 是无序的,所以就不能根据联合索引来确定到底该取哪一行。

二、小结

根据上述使用示例,可以得出,最左匹配原则有以下特性:

  • 最左优先:以最左边的字段为起点,任何连续的索引都能匹配上。
  • 范围查询字段后停止:当遇到 >、<、BETWEEN、LIKE之后,下一个列就不会再使用索引进行匹配。

三、索引下推:

  在搞清楚"联合索引中,前一个索引列使用了范围查询后,下一个索引列将无法使用索引进行快速定位"的问题后,我对上述示例6中的 SQL select * from test where a = 1 and b > 3 and c = 2; 进行了执行计划分析,如下:

  这个 Using index condition 就是我们接下来要讨论的东西。

  我们已知,上述 SQL 会使用到联合索引 idx_abc 中的 a、b 索引列,但是 c 索引列不会使用索引进行匹配。那么对于 where 条件中的 c = 2 该怎么处理呢?

  在 MySQL 5.6 之前,我们通过非聚簇索引 + 聚簇索引定位到一条记录后,会将行数据返回给 Server 层,Server 层会根据 c = 2 对数据进行过滤,只要符合条件的记录才会被返回给客户端,此时的 Extra 中的信息应为 Using where。

  但是从 MySQL 5.6 开始,引入了索引下推 (Index Condition Pushdown,ICP)来进行查询优化,最主要的区别是,对于索引列 c 的处理不会再让 Server 层去处理了,而是下推到存储引擎层,即在对联合索引进行数据匹配时,直接对使用不到索引的索引列条件进行判断,最后的结果就是只对符合条件的记录进行回表,这样的话就可以大大减少回表的次数,从而提升查询效率。

总结:

  • 索引下推 (ICP) 是 MySQL 5.6 引入的一项关键的查询优化技术。​​
  • ​​核心思想:​​ 将部分可以由索引包含的列完成的 WHERE 条件过滤操作,从服务器层“下推”到存储引擎层执行。
  • ​​主要应用场景:​针对联合索引 (INDEX (col1, col2, ...)) 的查询,特别是当 WHERE 条件中:
    • 查询使用了索引的第一列(通常是范围查询:>, >=, <, <=, BETWEEN, LIKE 'a%'),并且
    • 后面还包含其他索引列作为​​等值(=)​​或​​范围​​条件 (col2 = X, col3 > Y, etc.)
  • 可下推的条件:​​下推的条件需要是​​索引本身包含的列​​ (称为 Index Column)。在 idx_abc 例子中,c 是该索引的列,所以 c = 2 可以被下推。where a = 1 and b > 3 and c = 2 and d =7 中的 d = 7 因为 索引列不包含 b,所以其不能被下推。
  • ​​执行计划标识:​​使用 EXPLAIN 命令查看查询执行计划。如果看到 Extra 列显示 ​​Using index condition​​,则说明优化器对该查询使用了索引下推。
  • ​​巨大价值:​​它允许存储引擎在​​回表读取完整数据行之前​​,就利用索引中存储的后续列的值过滤掉大量不满足所有条件的记录,​​显著减少不必要的回表操作次数,从而大幅降低磁盘 I/O 和 CPU 开销,提升查询性能​​。

举例:

四、参考:

  • MYSQL最左匹配原则及其底层逻辑-CSDN博客
  • https://www.zhihu.com/question/52536048/answer/1906024782132125707

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 8.0 OCP 1Z0-908 题目解析(17)

题目65 Choose two. Which two are characteristics of snapshot-based backups? □ A) The frozen file system can be cloned to another virtual machine immediately into active service. □ B) There is no need for InnoDB tables to perform its own recovery when re…

Level2_12小球与挡板(移动+反弹)

一、前引 #已经学习完了: #1.数据结构&#xff1a;集合、元组、字典 #2.函数 #3.类和对象 #4.继承与多态 #1.规划编程项目: #&#xff08;1&#xff09;你想做什么什么样功能的项目&#xff1f; # 接小球游戏,碰到挡板时自动反弹 #&#xff08;2&#xff09;功能有哪些&#x…

win11 2025开机禁用微软账号登录,改本地用户登录,品牌预装机福音

今天开箱了品牌商出厂系统一台华为笔记本&#xff0c;开机提示连接wifi并需要登录微软账号&#xff0c;其中过程实在缓慢&#xff0c;而且老是提示自动更新&#xff0c;速度太慢了&#xff0c;等的花都谢了&#xff0c;进到桌面大概得要30-40分钟&#xff0c;还不如本地用户登录…

【嵌入式ARM汇编基础】-ELF文件格式内部结构详解(三)

ELF文件格式内部结构详解(三) 文章目录 ELF文件格式内部结构详解(三)12、动态部分和动态加载13、依赖加载(需要)14、程序重定位14.1 静态重定位14.2 动态重定位14.3 全局偏移表 (GOT)14.4 过程链接表 (PLT)12、动态部分和动态加载 ELF 文件格式中的 .dynamic 部分用于指…

HTML知识复习2

文章目录 HTML5简介什么是HTML5HTML5优势 新增语义化标签新增布局标签新增状态标签新增列表标签新增文本标签 新增表单功能表单控件新增属性input新增属性值 新增多媒体标签视频标签音频标签 HTML5兼容性处理 HTML5简介 什么是HTML5 HTML5 是新一代的 HTML 标准&#xff0c;2…

栈(Stack)和队列(Queue)

文章目录 前言1. 栈(Stack)1.1 什么是栈1.2 栈的常用操作1.3 栈的模拟实现1.4 栈的应用场景1.4.1 元素序列处理1.4.2 字符串反转1.4.3 括号匹配1.4.4 逆波兰表达式求值1.4.5 栈的压入、弹出序列1.4.6 最小栈1.4.7 递归转循环 1.5 概念区分1.5.1 数据结构中的栈1.5.2 JVM中的虚拟…

5G MEC四大核心挑战技术解析报告

一、MEC园区部署挑战:数据本地化与低时延接入 痛点深度解析 数据不出园区:工业质检、医疗影像等敏感业务需数据在本地闭环处理。但运营商基站与企业MEC间若经公网绕行,时延超50ms且存在泄露风险。L2网络局限:传统L2接入网无法实现基站→UPF的智能路由,导致业务流绕行城域…

【硬核拆解】英伟达Blackwell芯片架构如何重构AI算力边界?

前言 前些天发现了一个巨牛的人工智能免费学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 一、Blackwell诞生的算力危机&#xff08;2025现状&#xff09; graph TD A[2025年AI算力需求] --> B[千亿参数模型训练能耗…

【深度学习模块】图像的相对位置编码

这个是一个常用的模块&#xff0c;就是我们可以对输入的特征嵌入位置编码。 位置编码&#xff08;Positional Encoding&#xff09;是一种将空间位置信息嵌入到特征中的方法&#xff0c;通常用于帮助模型更好地理解特征的空间关系。 这里介绍的这个是相对位置编码&#xff0c;…

osg加入实时光照SilverLining 天空和3D 云

OSG系列文章目录 文章目录 OSG系列文章目录一、前言官网的介绍&#xff1a; 二、编译官网例子 一、前言 osg本身也可以加入动态云&#xff0c;但是效果有点差强人意&#xff0c;这里我们使用sundog公司的动态云&#xff1a;SilverLining 天空和 3D 云。 官网的介绍&#xff1…

spring-ai-alibaba 1.0.0.2 学习(十二)——聊天记忆扩展包

学习spring-ai时提到过&#xff0c;spring-ai除了内置的InMemoryChatMemoryRepository&#xff0c;还提供jdbc、cassandra、neo4j三个扩展包。 而spring-ai-alibaba则提供了jdbc、redis、elasticsearch三个扩展包。 两者都提供了jdbc扩展包&#xff0c;有什么区别呢&#xff…

c语言-指针(数组)练习2

题目&#xff1a;将数组中n个元素按逆序存放并打印出来&#xff0c;使用函数封装与指针 思路&#xff1a; 1.定义一个数组arr[5]和用于存放数组大小&#xff08;数组大小通过sizeof关键字来进行计算&#xff09;的变量len&#xff1b; 2.创建三个函数initArr、printArr、rev…

Redis服务器

Redis&#xff0c;一款Key-Value型内存数据库 常用于网站开发场景 Redis服务器只发布了Linux版本 Redis服务器安装&#xff0c;2种办法 自动安装 apt install redis-server手动编译安装 从官网下载源码&#xff0c;编译&#xff0c;部署 1 安装redis apt install redis-s…

LeetCode 第91题:解码方法

题目描述&#xff1a; 一条包含字母A-Z的消息通过以下映射进行了编码 1-A ...... 26-Z 要特别注意&#xff0c;11106可以映射为AAJF或KJF 06不是一个合法编码 给你一个只含数字的非空字符串s&#xff0c;请计算并返回解码方法的总数。如果没有合法的方法解码整个字符串&#xf…

Rocky Linux 9 源码包安装Mysql8

Rocky Linux 9 源码包安装Mysql8 大家好我是星哥&#xff0c;之前介绍了&#xff0c;Rocky Linux 9 源码包安装Mysql5.7。 本文将介绍如何在Rocky Linux 9操作系统上&#xff0c;从源码一步步安装MySQL 8&#xff0c;为您提供一个稳定、高效且可控的数据库解决方案。 为什么…

AI小智项目全解析:软硬件架构与开发环境配置

AI小智项目全解析&#xff1a;软硬件架构与开发环境配置 一、项目整体架构 AI小智是一款基于ESP32的智能物联网设备&#xff0c;集成了语音交互、边缘计算等功能。整体系统架构如下&#xff1a; 终端设备&#xff1a;ESP32模组作为核心通信方式&#xff1a; WebSocket实现实…

设计模式之上下文对象设计模式

目录 一、模式介绍 二、架构设计 三、Demo 示例 四、总结 一、模式介绍 上下文对象&#xff08;Context Object&#xff09;模式 最早由《Core J2EE Patterns》第二版提出&#xff0c;其核心目标是在多层或多组件间共享与当前作用域&#xff08;如一次请求、一次会话、一次…

@Linux服务器加域退域

文章目录 **一、加入Active Directory域****1. 准备工作****2. 配置步骤****步骤1&#xff1a;验证网络和DNS****步骤2&#xff1a;发现域****步骤3&#xff1a;加入域****步骤4&#xff1a;配置SSSD&#xff08;可选&#xff09;****步骤5&#xff1a;配置sudo权限&#xff08…

鸿蒙系统(HarmonyOS)4.2 设备上实现无线安装 APK 并调试

在鸿蒙系统&#xff08;HarmonyOS&#xff09;4.2 设备上实现无线安装 APK 并调试的步骤与 Android 类似&#xff0c;但需注意鸿蒙系统的特殊设置。以下是详细操作指南&#xff1a; 鸿蒙系统特殊准备 开启开发者选项&#xff1a; - 设置 > 关于手机 > 连续点击"H…

MyBatis时间戳查询实战指南

在 MyBatis 中通过时间戳&#xff08;Timestamp&#xff09;作为查询条件&#xff0c;需注意数据库时间类型与 Java 类型的映射。以下是具体实现方式&#xff1a; 一、Java 实体类与数据库字段映射 实体类定义 使用 java.sql.Timestamp 或 java.time.LocalDateTime&#xff08;…