B+树的物理排序方式决定联合索引必须遵循最左前缀原则:索引按定义顺序字典排序,查询条件需从左开始连续匹配等值或范围条件,否则右侧列无法参与定位,仅能ICP过滤。

不是MySQL“规定”必须遵守最左前缀,而是B+树的物理排序方式决定了它只能这么用。
联合索引在磁盘上就是一棵按字典序排列的B+树
比如索引 (status, create_time, user_id),InnoDB 存储时就严格按这个顺序排序:先排 status,status 相同的再排 create_time,前两者都相同的才排 user_id。这不是优化器“选不选”的问题,是数据本身在磁盘上就这么组织的。
这就意味着:
-
WHERE create_time = '2025-01-01'——create_time值散落在不同status分组里,无法二分查找,只能全扫 -
WHERE status = 'done' AND user_id = 100——user_id在status = 'done'的子集内仍是乱序的(因为中间缺了create_time),所以它不参与定位,只可能靠 ICP 在叶子节点过滤 -
WHERE status > 'done' AND create_time = '2025-01-01'——status是范围,对应多个不连续的子树,create_time = ...在这些子树中整体无序,无法加速
EXPLAIN里看得到的两个关键指标
验证是否真正走索引,不能只看 key 字段非空,得盯住 key_len 和 Extra:
-
key_len显示实际用于定位的字节数。比如status是 VARCHAR(20),utf8mb4 下最多占 80 字节;若查询只用到status,key_len就是 80;若三列全匹配,它会明显更大 -
Extra: Using where出现在key有值但key_len偏小的时候,说明右侧列没参与索引查找,只是 Server 层回表后逐行判断 -
Extra: Using filesort表示ORDER BY字段顺序和索引定义不一致,比如索引是(a, b, c)却写ORDER BY b, c
等值、范围、缺失这三类条件对索引链的影响
联合索引的匹配是一条“链”,从左到右逐列生效,但会被三类操作截断:
-
=或IN:可延续链,如WHERE a = 1 AND b = 2 AND c = 3→ 三列全用 -
>、<、BETWEEN、LIKE 'prefix%':链在此中断,右侧列失效(仅剩ICP过滤能力),如WHERE a = 1 AND b > 2 AND c = 3→c不定位 - 跳过某列(如
WHERE a = 1 AND c = 3):中间列b缺失,c立即失效,key_len不含c长度
注意:WHERE 子句中条件的书写顺序不影响匹配——优化器会重排;但索引定义顺序和查询条件是否覆盖最左连续列,才是硬约束。
ORDER BY 和 GROUP BY 同样受制于索引顺序
索引的排序能力只对“从左开始连续”的字段有效:
-
INDEX(a, b, c)可支持ORDER BY a、ORDER BY a, b、ORDER BY a, b, c(免 filesort) -
ORDER BY b, c或ORDER BY a, c都无法利用索引有序性,必触发Using filesort -
GROUP BY同理,且 MySQL 8.0+ 对 loose index scan 的要求更严,不满足最左前缀就退化为临时表 + filesort
最易被忽略的一点:即使 WHERE 条件完美匹配最左前缀,只要 ORDER BY 或 GROUP BY 字段顺序错位,性能损失就已发生——执行计划不会骗人,但人容易只看 type 和 key,漏掉 Extra 里的关键提示。


















