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