复合索引顺序需遵循最左前缀原则,高选择性字段优先靠左,等值条件置于范围条件左侧,并兼顾order by和覆盖查询需求。

复合索引的顺序不是随便排的,核心是让 MySQL 能真正用上它——关键看查询条件怎么写、字段筛选效果如何、以及是否要排序。
最左前缀必须守牢
MySQL 只能从索引最左边的列开始连续匹配,中间不能断。比如索引是 (user_id, status, create_time):
- WHERE user_id = 123 ✅ 能用上
- WHERE user_id = 123 AND status = 1 ✅ 前两列都用上
- WHERE user_id = 123 AND create_time > '2024-01-01' ✅ user_id 和 create_time 都参与,但 status 被跳过,所以 status 不走索引
- WHERE status = 1 ❌ 没有 user_id,整个索引失效
- WHERE user_id = 123 AND create_time = '2024-01-01' ❌ 缺了中间的 status,create_time 不走索引
高选择性字段尽量放最左
选择性 = COUNT(DISTINCT 列) / COUNT(*),越接近 1,说明这个字段值越分散、过滤能力越强。比如 user_id 通常比 status 更适合放前面:
- status 可能只有 0/1/2 几个值,选择性低,放后面更合适
- 手机号、订单号、时间戳这类唯一性或接近唯一的字段,优先靠左
- 可以用这条 SQL 快速评估:SELECT COUNT(DISTINCT status)/COUNT(*) AS sel_status FROM orders;
等值条件优先于范围条件
一旦遇到 >、LIKE '%abc'),它右边的所有列就不再走索引了:
- 索引 (a, b, c),查询 WHERE a = 1 AND b > 10 AND c = 3 → 只有 a 和 b 生效,c 不走索引
- 所以把等值条件(=)放在左边,范围条件(>、
- 如果业务中常查 WHERE city = 'SZ' AND age BETWEEN 25 AND 35,建议索引设为 (city, age),而不是 (age, city)
兼顾 ORDER BY 和覆盖查询
如果查询带排序,且排序字段顺序和索引一致,就能避免 Using filesort;如果 SELECT 的字段全在索引里,还能直接走 Using index(不用回表):
- SELECT * FROM orders WHERE user_id = 123 ORDER BY create_time DESC → 索引 (user_id, create_time) 同时满足过滤+排序
- SELECT name, email FROM users WHERE dept = 'tech' → 索引 (dept, name, email) 就是覆盖索引,查得快还省 IO
- 注意:ORDER BY 的方向(ASC/DESC)要和索引定义一致才稳定生效,混合方向可能不触发索引排序










