复合索引是否提速取决于查询条件是否匹配最左前缀及字段选择性:必须从索引首字段连续匹配,跳过左侧字段则索引失效;字段顺序应按高频等值查询、高区分度、范围查询由左至右排列。

直接加复合索引不一定提速,关键看查询条件是否匹配索引的最左前缀顺序,以及字段选择性是否足够高。
复合索引必须满足最左前缀才能生效
MySQL 的 B+ 树 索引结构决定了:只有查询条件从索引定义的**第一个字段开始连续出现**,索引才可能被使用。跳过左侧字段(哪怕只跳一个),该索引就基本失效。
-
CREATE INDEX idx_user_status_time ON orders(user_id, status, create_time)→ 查询WHERE user_id = 123 AND status = 'PAID'✅ 用到前两列 - 同上索引 → 查询
WHERE status = 'PAID' AND create_time > '2026-01-01'❌ 完全不走索引(user_id缺失) - 同上索引 → 查询
WHERE user_id = 123 AND create_time > '2026-01-01'⚠️ 只用到user_id,create_time因中间断开无法利用
字段顺序不能凭感觉排,得按区分度和查询模式定
复合索引的字段顺序直接影响命中率和效率。高频等值查询字段放最左,范围查询字段靠右,高选择性字段优先——不是“业务重要性”排序。
- 用户表中
gender(仅男/女)和age(0–120)都常查,但age区分度高得多 → 应建idx_age_gender,而非反过来 - 订单表常查
status = 'PAID'+create_time BETWEEN ...→status是低区分度字段(几个固定值),不适合放最左;若业务真需要这类组合,应单独建idx_status_time,并接受它不如idx_user_status高效 - MySQL 8.0+ 支持
Index Skip Scan,但只在最左列值极少(如
覆盖索引能省掉回表,但要小心字段膨胀
如果查询只涉及索引包含的所有列,MySQL 直接从索引树返回结果,无需回聚簇索引查整行 —— 这就是覆盖索引。但它不是“越多字段越好”。
- 原查询:
SELECT user_id, status, amount FROM orders WHERE user_id = 1005→ 建idx_user_status_amount可覆盖,EXPLAIN显示Using index - 但如果把
content TEXT或memo VARCHAR(2000)加进索引,会导致索引体积暴增、写入变慢、缓存命中率下降 - 原则:只把
SELECT列和WHERE条件列放进复合索引,避免冗余大字段;ORDER BY和GROUP BY字段也可纳入,但需验证是否真被优化器使用
真正卡住性能的,往往不是没建索引,而是建了却因字段顺序错、条件写法错或类型隐式转换导致索引完全失效。每次加索引前,先用 EXPLAIN 看执行计划,比盲目堆索引有用得多。











