【Java 开发日记】我们来说一说什么是联合索引最左匹配原则?

【Java 开发日记】我们来说一说什么是联合索引最左匹配原则?

目录

什么是联合索引?

什么是最左匹配原则?

核心要点:

举例说明

✅ 场景一:完全匹配最左列

✅ 场景二:匹配所有列

✅ 场景三:匹配最左连续列

❌ 场景四:跳过最左列

⚠️ 场景五:包含最左列,但中间有断档

⚠️ 场景六:最左列是范围查询

总结与最佳实践


什么是联合索引?

首先,要理解最左匹配原则,得先知道什么是联合索引。

  • 单列索引:只针对一个表列创建的索引。例如,为 users 表的 name 字段创建一个索引。
  • 联合索引:也叫复合索引,是针对多个表列创建的索引。例如,为 users 表的 (last_name, first_name) 两个字段创建一个联合索引。

这个索引的结构可以想象成类似于电话簿或字典。电话簿是先按姓氏排序,在姓氏相同的情况下,再按名字排序。你无法直接跳过姓氏,快速找到一个特定的名字。

什么是最左匹配原则?

最左匹配原则指的是:在使用联合索引进行查询时,MySQL/SQL数据库从索引的最左前列开始,并且不能跳过中间的列,一直向右匹配,直到遇到范围查询(><BETWEENLIKE)就会停止匹配。

这个原则决定了你的 SQL 查询语句是否能够使用以及如何高效地使用这个联合索引。

核心要点:
  1. 从左到右:索引的使用必须从最左边的列开始。
  2. 不能跳过:不能跳过联合索引中的某个列去使用后面的列。
  3. 范围查询右停止:如果某一列使用了范围查询,那么它右边的列将无法使用索引进行进一步筛选。

举例说明

假设我们有一个 users 表,并创建了一个联合索引 idx_name_age,包含 (last_name, age) 两个字段。

id

last_name

first_name

age

city

1

Wang

Lei

20

Beijing

2

Zhang

Wei

25

Shanghai

3

Wang

Fang

22

Guangzhou

4

Li

Na

30

Shenzhen

5

Zhang

San

28

Beijing

索引 idx_name_age 在磁盘上大致是这样排序的(先按 last_name 排序,last_name 相同再按 age 排序):

(Li, 30) (Wang, 20) (Wang, 22) (Zhang, 25) (Zhang, 28)

现在,我们来看不同的查询场景:

场景一:完全匹配最左列
SELECT * FROM users WHERE last_name = 'Wang';
  • 分析:查询条件包含了索引的最左列 last_name
  • 索引使用情况:✅ 可以使用索引。数据库可以快速在索引树中找到所有 last_name = 'Wang' 的记录((Wang, 20)(Wang, 22))。
场景二:匹配所有列
SELECT * FROM users WHERE last_name = 'Wang' AND age = 22;
  • 分析:查询条件包含了索引的所有列,并且顺序与索引定义一致。
  • 索引使用情况:✅ 可以高效使用索引。数据库先定位到 last_name = 'Wang',然后在这些结果中快速找到 age = 22 的记录。
场景三:匹配最左连续列
SELECT * FROM users WHERE last_name = 'Zhang';
  • 分析:虽然只用了 last_name,但它是索引的最左列。
  • 索引使用情况:✅ 可以使用索引。和场景一类似。
场景四:跳过最左列
SELECT * FROM users WHERE age = 25;
  • 分析:查询条件没有包含索引的最左列 last_name
  • 索引使用情况:❌ 无法使用索引。这就像让你在电话簿里直接找所有叫“伟”的人,你必须翻遍整个电话簿,也就是全表扫描
⚠️ 场景五:包含最左列,但中间有断档
-- 假设我们有一个三个字段的索引 (col1, col2, col3) -- 查询条件为 WHERE col1 = 'a' AND col3 = 'c';
  • 分析:虽然包含了最左列 col1,但跳过了 col2 直接查询 col3
  • 索引使用情况:✅ 部分使用索引。数据库只能使用 col1 来缩小范围,找到所有 col1 = 'a' 的记录。对于 col3 的过滤,它无法利用索引,需要在第一步的结果集中进行逐行筛选。
⚠️ 场景六:最左列是范围查询
SELECT * FROM users WHERE last_name > 'Li' AND age = 25;
  • 分析:最左列 last_name 使用了范围查询 >
  • 索引使用情况:✅ 部分使用索引。数据库可以使用索引找到所有 last_name > 'Li' 的记录(即从 Wang 开始往后的所有记录)。但是,对于 age = 25 这个条件,由于 last_name 已经是范围匹配,age 列在索引中是无序的,因此数据库无法再利用索引对 age 进行快速筛选,只能在 last_name > 'Li' 的结果集中逐行检查 age

总结与最佳实践

最左匹配原则的本质是由索引的数据结构(B+Tree) 决定的。索引按照定义的字段顺序构建,所以必须从最左边开始才能利用其有序性。

如何设计好的联合索引?

  1. 高频查询优先:将最常用于 WHERE 子句的列放在最左边。
  2. 等值查询优先:将经常进行等值查询(=)的列放在范围查询(><LIKE)的列左边。
  3. 覆盖索引:如果查询的所有字段都包含在索引中(即覆盖索引),即使不符合最左前缀,数据库也可能直接扫描索引来避免回表,但这通常发生在二级索引扫描中,效率依然不如最左匹配。

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

Read more

Visual Studio C++ 项目“添加现有项“避坑指南

Visual Studio C++ 项目"添加现有项"避坑指南 问题现象:文件在 VS 里能看到,但编译报错 No such file or directory 适用环境:Visual Studio 2019/2022/2026 + C++ 多项目解决方案 更新时间:2026-02-17 🕳️ 核心大坑 坑点 1:添加现有项 ≠ 复制文件 你以为的实际发生的文件会被复制到项目目录文件仍在原位置项目"拥有"了这个文件项目只是"引用"了这个文件移动项目也没问题原文件移动/删除后链接断裂 坑点 2:文件类型过滤 “添加现有项"对话框默认过滤文件类型,导致文件&

By Ne0inhk
告别 “理论选手”:用 g-note 打通 Java 中高级技术的任督二脉

告别 “理论选手”:用 g-note 打通 Java 中高级技术的任督二脉

告别 “理论选手”:用 g-note 打通 Java 中高级技术的任督二脉 * 前言 * 🎯 项目核心价值 * 📦 项目核心内容 * 📥 源码地址 * 🎬 项目展示 * 📝 总结 前言 作为 Java 程序员,进阶路上是不是总被这些痛点绊住脚步? * 📚 高并发场景仅停留在面试题,实战经验近乎空白,线上问题束手无策; * 🧩 源码晦涩冗长,硬啃几行就犯困,技术提升全靠 “三分钟热度”; * 💡 学过的知识点 “不用就忘”,零散不成体系,复盘时如同全新内容。 深知这些困境的折磨,我耗时整理并手撸了「g-note」学习仓库 —— 集理论、实践、源码、笔记于一体,目前仍在持续更新,现开源分享给大家,助力各位突破技术瓶颈。 🎯 项目核心价值 市面上多数教程要么纯理论堆砌,要么是零散 Demo,难以形成完整学习闭环。而 g-note 主打 “学练结合、体系化沉淀”

By Ne0inhk

Java Undertow 服务器 Host头注入高危漏洞(CVSS 9.6分) 完整分析与解决方案

一、漏洞核心信息(必看) ✅ 漏洞名称:Undertow HTTP Host 请求头注入漏洞(HTTP Host Header Injection) ✅ 漏洞定级:高危漏洞,CVSS 评分 9.6/10(该评分意味着漏洞利用简单、危害极大,属于必须立即修复的级别) ✅ 影响核心:Java 生态主流的高性能非阻塞 Web 服务器 Undertow,Spring Boot 项目首当其冲(因为 Spring Boot 2.x/3.x 版本默认的嵌入式 Web 服务器就是 Undertow/Tomcat,其中大量生产环境使用 Undertow) ✅ 漏洞本质:服务器对客户端传入的 Host 请求头未做严格合法性校验与清洗,直接采信并使用该参数,

By Ne0inhk