联合索引需按查询模式重排字段顺序,否则仅最左列生效;status非最左列时WHERE条件无法使用idx_user_status索引,必须添加单列索引;范围查询后字段失效,等值字段应前置以提升区分度和查询效率。

联合索引不是“字段堆得越多越好”,而是必须按查询模式重排顺序;不重排,90%的联合索引在真实 SQL 中只生效前 1 列。
为什么 WHERE status = 1 完全不走 idx_user_status(user_id, status)?
因为 status 不是最左列,B+ 树没法从它开始定位。MySQL 不会倒着扫描索引,也不会“跳过”user_id 去找 status —— 这不是优化器偷懒,是 B+ 树结构决定的硬约束。
- 执行
EXPLAIN SELECT * FROM orders WHERE status = 1时,type是ALL,key为空,就是全表扫描 - 即使你加了
ORDER BY status或GROUP BY status,只要没带上user_id = ?,索引依然无效 - 想让
status单独查快,就得补一个单列索引:KEY idx_status(status)
WHERE user_id = 1 AND order_date > '2023-01-01' 后面的 status 还能用索引吗?
不能。联合索引 (user_id, status, order_date) 中,order_date 是范围条件(>),它右边的所有列(这里没有)失效;但更关键的是,status 在 order_date 左边,却没出现在 WHERE 条件里 —— 它根本没机会被“激活”。
- 有效写法只有:
WHERE user_id = 1 AND status = 2 AND order_date > '2023-01-01'(status参与查找,order_date仅用于过滤) - 如果常查
user_id = ? AND order_date > ?,应把索引改为(user_id, order_date, status),让等值列在前、范围列居中、非关键列靠后 - 注意:
LIKE 'abc%'算范围行为,同样中断匹配
怎么判断该把哪个字段放最左边?看区分度,更要看查询频率
高区分度字段(如 user_id)放左,能快速切出小数据集;但如果业务里 80% 的查询是 WHERE status = ? AND created_at > ?,那 status 就得前置 —— 即使它只有 3 个枚举值。
- 用
SELECT COUNT(DISTINCT status)/COUNT(*) FROM orders粗估选择性: - 查慢查询日志或
performance_schema.events_statements_summary_by_digest,统计各 WHERE 组合出现频次 - 避免把
is_deleted TINYINT放最左:它通常只有 0/1,索引树第一层就分两支,后续下钻效率极低
最左匹配不是配置开关,是 B+ 树的物理现实。重排索引前,先确认哪些 SQL 真正在跑、哪些字段真正在过滤——否则建完才发现,WHERE 里永远缺那个“最左”的值。


















