联合索引必须严格满足最左匹配原则,即只能从最左侧连续字段开始使用,范围查询后右侧字段失效,且非最左字段单独查询无法使用该索引。

联合索引不是“只要字段都在就一定能用”,必须严格满足最左匹配,否则索引可能完全失效或仅部分生效。
什么是真正的最左匹配:从 B+ 树结构看起
联合索引 (a,b,c) 在底层是一棵按字典序排序的 B+ 树:先比 a,a 相同再比 b,b 相同再比 c。MySQL 只能从最左侧连续地“切片”这棵树。
这意味着有效使用场景只有这些:
-
WHERE a = ?—— 匹配(a)子索引 -
WHERE a = ? AND b = ?—— 匹配(a,b)子索引 -
WHERE a = ? AND b = ? AND c = ?—— 匹配完整(a,b,c) -
WHERE a = ? AND b > ? AND c = ?——c不会走索引(范围查询后中断)
而以下写法基本等于没用这个联合索引:
-
WHERE b = ?或WHERE c = ?—— 无法定位树根,全表扫描 -
WHERE a = ? AND c = ?——b缺失,c无法下钻,只用到a -
WHERE a > ? AND b = ?——b在范围之后,不参与索引查找
为什么 status = 1 单独查会忽略 idx_user_status?
假设你建了联合索引 idx_user_status(user_id, status),但执行 EXPLAIN SELECT * FROM orders WHERE status = 1 时发现没走索引——这不是 bug,是机制使然。
因为 status 不是最左列,B+ 树根本没法从 status 开始定位。MySQL 优化器不会“倒着遍历”索引树。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
此时你要么:
- 补一个单列索引
KEY idx_status(status)(适合高频单查status的场景) - 重构查询逻辑,确保带上
user_id(比如加个默认值或业务兜底) - 确认是否真需要查所有
status=1的行;如果只是统计数,可考虑覆盖索引 +COUNT(*)减少回表
等值 + 范围混合时,最左匹配的临界点在哪?
联合索引 (a,b,c) 中,一旦出现范围条件(>、、<code>BETWEEN、LIKE 'abc%'),它右边的所有列都**自动失效**,不能再用于索引查找。
例如:
-
WHERE a = 1 AND b > 10 AND c = 20→ 只用到a和b,c不参与查找(但可用于过滤) -
WHERE a > 1 AND b = 10→ 只用到a,b完全无效 -
WHERE a = 1 AND b LIKE 'x%' AND c = 5→c无效(LIKE 'x%'是范围行为)
所以建索引时,要把等值条件列放在左边,范围列靠右,且尽量只留一个范围列在末尾。
怎么验证你的查询到底用了哪些索引列?
别只信 EXPLAIN 的 key 字段显示了索引名,关键要看 key_len 和 Extra:
-
key_len值能反推出用了几列:比如user_id是 INT(4 字节),status是 TINYINT(1 字节),那么key_len = 4表示只用了user_id;key_len = 5表示用了前两列 -
Extra出现Using index→ 覆盖索引,没回表;出现Using where; Using index→ 索引里做了部分过滤;只有Using where→ 索引只定位,后续靠引擎层逐行判断 - 用
EXPLAIN FORMAT=JSON查看used_columns和range_analysis,更准
真正容易被忽略的是:即使 EXPLAIN 显示走了索引,如果 key_len 比预期小,或者 rows 高得离谱,大概率是“表面走索引,实际只用左一列”。

















