当前位置: 首页 > news >正文

最左匹配原则:复合索引 (a,b,c) 在 a=? AND b>? AND c=? 查询下的使用分析

查询条件是:WHERE a = ? AND b > ? AND c = ?,当我们查询时,一定能走到索引吗?有几个字段能走到索引?

直接回答:

  1. 能走到索引吗? ,这个查询一定会使用 (a, b, c) 索引。
  2. 走到索引的有几个? 精确地说,索引中的 前两个字段(a 和 b) 被用于“查找”(Range),第三个字段 c 被用于“过滤”(Filtering)。

下面我来详细解释为什么,这对于你理解复合索引的工作原理非常重要。


详细原理分析

MySQL 的 InnoDB 引擎使用 B+树 结构存储索引。对于复合索引 (a, b, c),它的排序方式是:

  • 首先按 a 字段排序。
  • a 相同的情况下,按 b 字段排序。
  • ab 都相同的情况下,才按 c 字段排序。

你的查询条件是:WHERE a = ? AND b > ? AND c = ?

索引的查找过程可以分解为三个层面:Index KeyIndex Filter, 和 Table Filter

1. Index Key (索引查找 - 用于确定扫描范围)

这是索引最核心的作用。MySQL 会利用索引的最左前缀原则来定位到需要扫描的数据范围。

  • a = ?:这是一个等值查询。引擎能利用索引快速定位到所有 a 等于特定值的叶子节点区域。这是第一层精确筛选。
  • b > ?:这是一个范围查询。在 a 已经固定的前提下,索引中的数据是按 b 排序的。因此,引擎可以在这个 a 固定的区域内,快速找到 b 大于某个值的起始点,然后从这个起始点开始向后扫描,直到这个 a 区域的结束点。

到这一步为止,索引 (a, b) 的部分被完美地用于快速定位和扫描。 这就是为什么我们说索引“走了”两个字段。

2. Index Filter (索引过滤 - 在扫描范围内筛选)

现在,引擎已经在扫描所有满足 a = ? AND b > ? 的记录索引项了。但是我们的查询还有第三个条件 c = ?

  • 虽然 c 也在索引中,但由于 b 是范围查询,导致 c 的相对顺序在索引中失效了。也就是说,在 b > ? 的范围内,c 的值并不是有序的。
  • 因此,MySQL 无法再使用索引树来快速定位 c = ? 的记录(即无法对 c 进行“查找”)。
  • 但是,InnoDB 仍然可以做 “索引条件下推”(Index Condition Pushdown, ICP)。这意味着,引擎会在读取索引页的时候,就顺便判断一下这条索引记录中的 c 字段是否等于 ?。如果不等于,则直接跳过,根本不需要回表

所以,字段 c 也被用到了,但它不是在“查找”层面,而是在“过滤”层面。 它的作用是极大减少了需要回表查询主键的数据行数。

3. Table Filter (表过滤 - 回表后筛选)

如果查询还包含了 SELECT * 或者表中其他不在索引中的字段,那么对于通过 Index Filter 筛选后的记录,引擎还需要通过主键回表去读取完整的数据行。

如果表中还有其他查询条件(例如 AND d = ?),而 d 不在索引中,那么这些条件会在回表读取到完整数据行之后再进行过滤。

在你的例子中,由于 WHERE 条件已经结束,通常到 Index Filter 就完成了。


总结与可视化

假设我们有一个 (a, b, c) 索引,数据如下:

abc
115
124
133
144
211

查询 a=1 AND b>1 AND c=4

  1. Index Key (查找):通过索引树快速定位到 a=1 的子树,然后在该子树内找到 b>1 的起始点(即 (1,2,4) 这条记录)。从此开始向后扫描,直到 a != 1
  2. Index Filter (过滤):在扫描 (1,2,4), (1,3,3), (1,4,4) 这些索引项时,直接检查索引中的 c 值。(1,2,4)c=4,符合;(1,3,3)c=3,不符合,跳过;(1,4,4)c=4,符合。
  3. 结果:最终只需要为 (1,2,4)(1,4,4) 这两条索引记录回表(如果需要的话)。

结论

字段索引使用方式
a等值查找 (Index Key)
b范围查找 (Index Key)
c索引过滤 (Index Filter,利用ICP)

所以,这个索引 (a, b, c) 对本次查询是有效的,三个字段都发挥了作用。但通常我们说“走了几个字段的索引”指的是用于“查找”(Index Key)的字段,所以严格来说是 2个(a和b)

优化建议:
如果 c 的选择性非常高(即几乎每条记录的 c 值都不同),而 b 的范围很大,你可以考虑建立一个 (a, c, b) 的索引。这样查询条件变成 a = ? AND c = ? AND b > ?,所有三个字段都可以用于等值查找和范围查找,效率可能更高。但这需要结合你的具体数据分布来判断。

http://www.dtcms.com/a/365732.html

相关文章:

  • 波浪模型SWAN学习(2)——波浪浅化模拟(Shoaling on sloping beach)
  • 14.错误和异常(二)
  • PastePal for Mac 剪贴板历史记录管理器
  • 学习嵌入式第四十五天
  • 设计原则与设计模式
  • flume拓扑结构详解:从简单串联到复杂聚合的完整指南
  • 蓝牙modem端frequency offset compensation算法描述
  • 技术重构人力管理 —— 打造人力资源流程自动化、智能化专业服务方案
  • 小企业环境-火山方舟和扣子
  • 字节跳动后端 一面凉经
  • 数据库与大数据技术栈
  • ElasticSearch倒排索引原理
  • redis中五大数据类型的操作命令
  • 编程基础-eclipse创建第一个程序
  • 【开题答辩全过程】以 基于java的隔离酒店管理系统设计与开发为例,包含答辩的问题和答案
  • 线程通信机制
  • 记录一下node后端写下载https的文件报错,而浏览器却可以下载。
  • 开源与闭源的再对决:从Grok到中国力量,AI生态走向何方?
  • 并发编程指南 同步操作与强制排序
  • Claude Code初体验:让AI成为你的结对程序员
  • Linux学习——管理基本存储(十八)
  • A股大盘数据-2025093分析
  • Provider中的watch、read、Consumer、ChangeNotifierProvider、ValueNotifierProvider
  • 信息融智学=信息哲学+信息科学+信息技术+信息系统工程+信息处理之智
  • 数据库选择有讲究?SQLite、PostgreSQL还是MySQL?
  • 全渠道 + 低代码:如何打造 “内外协同” 的客服管理系统体系?
  • http和https区别是什么
  • docker 安装 redis 并设置 volumes 并修改 修改密码(三)
  • 【TypeScript】事件循环
  • k8s的SidecarSet配置和initContainers