惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
T
Tailwind CSS Blog
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
博客园 - 叶小钗
N
Netflix TechBlog - Medium
罗磊的独立博客
量子位
MyScale Blog
MyScale Blog
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
V
Visual Studio Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
B
Blog
腾讯CDC
爱范儿
爱范儿
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
F
Fortinet All Blogs
雷峰网
雷峰网
G
Google Developers Blog
Google DeepMind News
Google DeepMind News

博客园 - 幽州散人

SQL优化案例 synchronized 为啥会让虚拟线程卸载失效 主线任务和使命 温州3日之旅 CompletableFuture + 异步Servlet:同步的姿势、异步的效果 Snowflake雪花算法与发号器的应用 windows Java 幽灵转发壳进程 也谈MySQL limit offset深翻页问题 SHOW SESSION STATUS 与 Handler 变量 MySQL 5.7 Profiles 执行性能分析 MySQL临时表与文件排序 MySQL 5.7 MRR多范围读优化 MySQL 5.7 ICP索引条件下推优化 从I/O 的物理成本理解回表和索引覆盖 第4个电瓶以及补漆 Flink原理:并行度与keyGroup桶 什么是数字批发银行 Java虚拟线程(三)实现原理 Java虚拟线程(二) Java虚拟线程(一) 大模型推理层服务化架构 传奇调查员之路:理智值-99,但我必须听懂深渊的语言 js里调用智能合约读/写函数的方法的区别 字节与其16进制字符表示转换的bug Redisson分布式锁 交易心得 DexScreener接口初探 某安全软件跑飞了。。 Ed25519算法签名与验签的Java实现 Tendermint拜占庭容错引擎
MySQL符合索引与最左前缀原则
幽州散人 · 2026-08-12 · via 博客园 - 幽州散人

对于联合索引 INDEX(a, b, c)

索引排序顺序:先按 a 排序,a 相同按 b 排序,b 相同按 c 排序

能用到索引的情况:
  WHERE a = 1                      ✅ 用到 a
  WHERE a = 1 AND b = 2            ✅ 用到 a, b
  WHERE a = 1 AND b = 2 AND c = 3  ✅ 用到全部
  WHERE a = 1 AND c = 3            ✅ 用到 a(c 不能跳过 b 单独用)
  WHERE a > 1 AND b = 2            ✅ a 范围后 b 失效(部分场景可用 ICP)

用不到索引的情况:
  WHERE b = 2                      ❌ 跳过 a
  WHERE c = 3                      ❌ 跳过 a, b
  WHERE b = 2 AND c = 3            ❌ 跳过 a

索引列的顺序 = 排序的优先级。跳过前面的列,后面的列无法用于索引查找。

因为复合索引用一个 B+Tree 实现了多级排序。想象一张排好序的纸质表格就懂了:


复合索引 (city, status) 的物理结构

索引 B+Tree 叶子节点按顺序排列:

city='Beijing'  status=0
city='Beijing'  status=0
city='Beijing'  status=1    ← Beijing 里面按 status 排序
city='Beijing'  status=1
city='Beijing'  status=1
────────────────────────────    ← 换下一个城市
city='Shanghai' status=0
city='Shanghai' status=1
city='Shanghai' status=1
────────────────────────────
city='Shenzhen' status=0
city='Shenzhen' status=0
city='Shenzhen' status=1
...100个城市,每个城市里面 status 有序...

问题一:跳过 city 直接查 status=1 为什么失效?

你问 B+Tree:把所有 status=1 的找出来

B+Tree 傻眼了:

city='Beijing' status=0 ← status=1 在哪?
city='Beijing' status=0 ← 这里?
city='Beijing' status=1 ← 这里?跳到后面再跳回来?
city='Beijing' status=1
──────────────────────
city='Shanghai' status=0
city='Shanghai' status=1 ← 这里有
city='Shanghai' status=1
──────────────────────
city='Shenzhen' status=0
city='Shenzhen' status=0
city='Shenzhen' status=1 ← 这里有
...

status=1 的行散落在 100 个城市各自的区间里,没有连续聚集在一起
→ 无法定位一个"连续区间" → 只能把整个索引扫一遍 → 失效

本质:不指定 city,B+Tree 里 status=1 的记录不连续,没法用 B+Tree 的"定位起点 → 顺序扫描"能力。


问题二:city 用了范围后,status 为什么也失效?

你问 B+Tree:city LIKE 'Bei%' AND status = 1

city 前缀匹配可能命中多个城市:

city='Bei...' status=? ← 可能有 Beijing, Beihai, Beilun...
city='Beijing' status=0
city='Beijing' status=0
city='Beijing' status=1 ← status=1
city='Beijing' status=1 ← status=1
─────────────────────────
city='Beihai' status=0
city='Beihai' status=0
city='Beihai' status=1 ← status=1
city='Beihai' status=1 ← status=1
─────────────────────────
city='Beilun' status=1 ← status=1
city='Beilun' status=1 ← status=1
...

status=1 在这个大范围内,按 city 排序,而不是按 status 排序
→ 无法连续定位所有 status=1 → 只能扫完整个 city 范围再逐个判断

本质:city 不精确(等值=一个区间),status 只在每个 city 区间内部有序,跨了 city 区间就不连续了。


一张图总结

最左前缀命中的条件:
  city = ?  AND  status = ?     ✅ 定位到连续区域
  city = ?  AND  status > ?     ✅ 同一个 city 内 status 连续
  city = ?                      ✅ 定位到 city 区间
  city > ?                      ✅ 定位到起始 city,顺序往后扫

失效的情况:
  status = ?                    ❌ 散落在 100 个 city 区间里
  city > ?  AND  status = ?     ❌ 多个 city 区间,status=1 不连续
  city LIKE '%x'                ❌ 无法定位起始位置

口诀:
等值查询 → 缩小范围 → 后面的列继续有效
范围查询 → 扩张到多个区间 → 后面的列只在各自区间内有序 → 无法用于缩小范围