联合索引必须满足最左前缀匹配,否则无法生效;B+树按索引列顺序整体排序,缺最左列则无法定位起点;列序影响命中率、排序复用及过滤效率,须结合选择性、等值/范围查询类型合理设计,并以EXPLAIN验证。

联合索引不是“有列就用”,而是必须满足最左前缀匹配
很多开发者以为只要 WHERE 里出现了联合索引中的某几列,MySQL 就会走索引——这是最常见的误判。实际上,KEY idx_name_age_status (name, age, status) 这个索引,只有以下情况能生效:
-
WHERE name = 'Alice'→ 走name列 -
WHERE name = 'Alice' AND age = 25→ 走name, age -
WHERE name = 'Alice' AND age = 25 AND status = 'active'→ 全部三列都走 -
WHERE name = 'Alice' AND status = 'active'→ 仅name有效,status不会跳过age单独使用 -
WHERE age = 25 AND status = 'active'→ 索引完全失效(缺最左列name)
根本原因是 B+ 树按 (name, age, status) 整体排序,没 name 就无法定位搜索起点。优化器不会“智能补全”,也不会重排条件顺序来适配索引。
多条件查询场景下,列顺序决定索引是否真正可用
联合索引的列序不是随便排的,它直接影响哪些查询能命中、哪些被强制回表或全表扫描。例如文章系统常见查询:
SELECT * FROM articles WHERE status = 'publish' AND category_id = 5 AND created_at > '2026-01-01'- 如果建索引为
KEY idx_status_cat_time (status, category_id, created_at),这个查询能用上全部三列 - 但如果建反了,比如
KEY idx_cat_status_time (category_id, status, created_at),那上面查询只用到category_id,后两列全部失效 - 更糟的是:如果
status只有 2–3 个取值(如 draft/publish/deleted),选择性极低,放前面反而降低过滤效率
优先把高选择性列(如 category_id、author_id)放最左;等值查询列(=)放前面,范围查询列(>、BETWEEN)靠后——因为范围列之后的字段自动失效。
ORDER BY 和 GROUP BY 能否复用联合索引,取决于字段顺序和方向一致性
文章列表页常带排序,比如 ORDER BY category_id, created_at DESC。这时候联合索引能不能省掉 filesort,关键看定义是否严格匹配:
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
-
KEY idx_cat_time (category_id, created_at)→ORDER BY category_id, created_at DESC在 MySQL 8.0+ 可用(支持混合方向) -
KEY idx_cat_time (category_id, created_at)→ORDER BY category_id DESC, created_at ASC在 MySQL 5.7 中会直接放弃索引排序 -
KEY idx_time_cat (created_at, category_id)→ORDER BY category_id, created_at完全不匹配最左前缀,必然 filesort - 注意:
WHERE和ORDER BY的字段必须共享同一个最左前缀,否则优化器不会合并使用
一个典型坑是:加了 WHERE status = 'publish',但索引是 (created_at, category_id),此时 ORDER BY created_at 虽然能用索引,但 WHERE 条件根本走不上——优化器大概率选全表扫描或临时索引合并,而非你预想的路径。
EXPLAIN 是唯一可信依据,别信“应该能走索引”这种猜测
即使 SQL 看起来完全符合最左前缀,也必须用 EXPLAIN 验证。重点看三列:
-
key字段是否显示你期望的联合索引名 -
key_len是否符合预期(比如idx_a_b_c上WHERE a = ? AND b = ?,key_len应该是 a+b 的字节数,不是只算 a) -
Extra是否出现Using filesort或Using temporary—— 出现就说明排序/分组没复用索引
特别提醒:MySQL 优化器可能因数据分布(如某列重复值过多)、统计信息过期、或查询代价估算偏差而放弃联合索引,改用索引合并(index_merge)甚至全表扫描。这时不能只调索引,得结合 ANALYZE TABLE 更新统计信息,或用 FORCE INDEX 强制验证效果。
最易被忽略的一点:联合索引生效的前提是查询条件中没有对索引列做函数操作或隐式类型转换,比如 WHERE DATE(created_at) = '2026-09-01' 或 WHERE category_id = '5'(字段是 INT,传入字符串),都会让整条索引失效。










