单列索引足够。where仅用一个字段时,建index(a)即可高效命中,无需提前建复合索引;复合索引虽能通过最左前缀匹配生效,但浪费空间和写入性能,且对where b = ?完全无效。

WHERE 条件里只用一个字段,该建单列索引还是复合索引?
单列索引足够。mysql、postgresql 等主流数据库对 WHERE a = ? 这类查询能高效命中 INDEX(a),不需要为了“以后可能加条件”提前建 INDEX(a, b)。复合索引在单字段查询时虽可能被用上(最左前缀匹配),但会浪费磁盘空间和写入开销,更新 b 字段时也要维护冗余索引项。
- 单列索引体积小,B+ 树层级更低,点查更快
- 复合索引
INDEX(a, b)对WHERE a = ?有效,但对WHERE b = ?完全无效 - 如果业务明确只按
a过滤,建INDEX(a)更干净;后续真要查a AND b,再补INDEX(a, b)也不迟
WHERE 同时过滤两个字段,为什么 INDEX(a, b) 比 INDEX(a) + INDEX(b) 快?
因为 MySQL 通常一次查询只用一个索引(5.7+ 的 index merge 是例外,但代价高、不可靠)。WHERE a = ? AND b = ? 用两个单列索引,优化器大概率退化为全表扫描或只选其一,再回表过滤另一个条件;而 INDEX(a, b) 能直接定位到唯一叶子节点,避免回表或二次过滤。
- 复合索引的 B+ 树按
a排序,a相同时再按b排序,天然支持等值+等值联合查找 -
INDEX(a)+INDEX(b)在AND场景下几乎不协同工作,除非走 index merge(查看执行计划里是否出现index_merge) - 注意顺序:
INDEX(a, b)对WHERE a = ? AND b = ?高效,但对WHERE b = ?无效
ORDER BY 和 WHERE 混用时,复合索引字段顺序怎么排?
优先满足 WHERE 的等值条件,再接 ORDER BY 字段。例如 WHERE status = 'active' ORDER BY created_at DESC,应建 INDEX(status, created_at)。这样索引能先快速定位所有 status = 'active' 的行,且这些行在索引中已按 created_at 排好序,无需额外排序。
- 等值条件(
=、IN)可作为索引前导列;范围条件(>、BETWEEN)之后的字段无法用于索引排序 -
WHERE a > 10 ORDER BY b用INDEX(a, b)时,b部分不参与排序(因为a是范围扫描,b在各a分组内有序,但跨组无序) - 如果
ORDER BY b DESC, c ASC,索引字段顺序必须严格对应,且方向需一致(MySQL 8.0+ 支持混合方向,但老版本只认全部 ASC 或全部 DESC)
建了复合索引,EXPLAIN 却显示没用上,常见原因有哪些?
最常见的是条件没触达最左前缀,或隐式类型转换导致索引失效。
-
WHERE b = ?不会用INDEX(a, b),哪怕b是第二列 - 字段类型和参数类型不一致:比如
user_id是BIGINT,但 SQL 里写成WHERE user_id = '123'(字符串),触发隐式转换,索引失效 - 对索引字段用了函数:
WHERE YEAR(created_at) = 2024无法用INDEX(created_at),应改写为WHERE created_at >= '2024-01-01' AND created_at - 使用了
!=、NOT IN、LIKE '%xxx'等无法走索引的表达式
索引不是建了就万事大吉,每条查询都得看 EXPLAIN 输出里的 key 和 rows 字段——前者告诉你用了哪个索引,后者暴露实际扫描行数,比“是否用索引”更能说明问题。