三星索引指满足where条件走索引(一星)、order by免排序(二星)、select列全被覆盖避免回表(三星)的复合索引,需通过explain验证type、key、rows和extra字段是否达标。

三星索引不是评分标准,而是执行路径是否高效的判断依据
直接说结论:EXPLAIN 输出里 type 是 ref 或更好、key 显示用了哪个索引、rows 接近实际匹配行数、Extra 没有 Using filesort 和 Using temporary —— 这才说明你写的 SQL 真正跑在了三星索引上。它不是“给索引打分”,而是看优化器有没有走最短路径。
一星:WHERE 条件列必须全部落在索引最左前缀中
常见错误是把 WHERE a = ? AND b > ? AND c = ? 的条件,建索引时写成 (a, c, b)。虽然三列都在索引里,但 b > ? 是范围查询,会截断最左前缀,导致 c 实际无法命中。
- 正确顺序应是
(a, b, c):等值列a、范围列b放前面,等值列c放后面(仍可利用索引排序) - 如果条件含
OR或函数,比如WHERE YEAR(create_time) = 2025,这一星就直接崩了 —— 索引失效,rows变成全表行数 - 低选择性列(如
status只有 0/1)放最左会导致索引片太宽,实际效果接近全表扫描
二星:ORDER BY 字段必须连续出现在索引尾部,且方向一致
比如 ORDER BY user_age DESC, user_name ASC,索引必须是 (..., user_age DESC, user_name ASC) 才能免排序。MySQL 不支持混合方向(DESC + ASC)的联合索引高效利用,除非全部统一方向。
-
ORDER BY user_age DESC能用(user_job, user_age),但不能用(user_age, user_job)—— 后者只有在WHERE user_age = ?时才生效 - 如果
WHERE用了user_job = ?,ORDER BY user_age DESC,索引(user_job, user_age)就同时满足一星和二星 -
GROUP BY同理,也依赖索引顺序;若出现Extra: Using temporary; Using filesort,基本就是二星没达标
三星:SELECT 列必须全部被索引覆盖,避免回表
这是最容易被忽略的一点。哪怕一星、二星都满足,只要 SELECT * 或查了没进索引的列,InnoDB 就得拿着主键回聚集索引捞完整行 —— 这个“回表”开销在大结果集下非常致命。
- 例如查询
SELECT user_name, user_phone FROM user WHERE user_job = '金融',索引必须是(user_job, user_name, user_phone),而不是只建(user_job) - 注意:主键列自动包含在二级索引中,所以
SELECT id, user_name可以用(user_job, user_name)——id不用显式写进去 - TEXT/BLOB 类型列不能建索引,一旦 SELECT 包含它们,三星必然失败;这类字段建议单独查,或用冗余字段存摘要
真正难的不是建索引,是让每条线上 SQL 都对齐这三条路径。一个 WHERE 条件变、一个 ORDER BY 加字段、一个前端多加个 SELECT 字段,都可能让原本高效的索引瞬间失效。别信“这个索引看起来很全”,EXPLAIN 一眼就能戳破幻觉。











