mysql中的多列索引与单列索引的应用场景

13次阅读

该用多列索引而非多个单列索引的情况是:查询条件为左前缀匹配(如WHERE a=?、a=? AND b=?等),且优化器默认不启用index_merge;单列索引适用于单独过滤、外键、ORDER/GROUP BY或高基数列;多列索引列序应按等值过滤性强弱降序排列,并用EXPLaiN验证实际使用效果。

mysql中的多列索引与单列索引的应用场景

什么时候该用多列索引而不是多个单列索引

mysql 的优化器通常不会同时使用多个单列索引去加速同一个查询(除非启用了 index_merge,但它是例外而非默认行为)。如果你常查 WHERE user_id = ? AND status = ?,建两个单列索引 (user_id)(status) 效果往往不如一个联合索引 (user_id, status)

关键看查询条件是否「左前缀匹配」:多列索引 (a, b, c) 能加速以下条件:

  • WHERE a = ?
  • WHERE a = ? AND b = ?
  • WHERE a = ? AND b = ? AND c = ?
  • WHERE a = ? AND b IN (?, ?) AND c = ?(c 仍可用)

但无法加速 WHERE b = ?WHERE b = ? AND c = ?(缺少最左列 a),此时索引失效。

单列索引更适合哪些场景

单列索引在以下情况更合适:

  • 该列频繁单独出现在 WHERE 条件中,且值分布较均匀(如 emailorder_no
  • 作为外键字段,需保证引用完整性(如 user_id 在订单表中)
  • 用于 ORDER BY colGROUP BY col,且不涉及其他过滤列
  • 列基数极高(如 UUID),而组合后区分度没明显提升,建联合索引反而浪费空间

注意:如果已有单列索引 (a),又新建了多列索引 (a, b),那原来的 (a) 索引大概率可以删掉——因为 (a, b) 已能覆盖所有 a 单独查询的需求,还省下一次索引维护开销。

多列索引的列顺序怎么定

顺序不是随便写的,直接影响索引能否命中。核心原则是:「过滤性越强、越常用于等值查询的列放前面」。

比如用户表有 status(只有 ‘active’/’inactive’)、created_at(时间戳)、user_id(唯一):

  • WHERE status = 'active' AND user_id = 123 → 推荐 (user_id, status),因为 user_id = ? 过滤性最强,能直接定位一行
  • WHERE created_at > '2024-01-01' AND status = 'active'(status, created_at) 更好,因为 status 是等值,created_at 是范围;MySQL 只能对多列索引中最左边的等值列之后的第一列用范围扫描

错误示例:(created_at, status)WHERE status = ? 完全无效;对 WHERE created_at > ? AND status = ? 也只能用上 created_atstatus 变成表扫描过滤。

如何验证索引是否真的被用了

别猜,用 EXPLAIN 看执行计划:

EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';

重点关注这几列:

  • key:显示实际使用的索引名
  • key_len:值越大,说明用到的索引列越多(例如 key_len=8 可能只用了第一列,key_len=12 表示前两列都参与了查找)
  • rows:预估扫描行数,越小越好
  • Extra:出现 using index 表示覆盖索引;出现 Using where; Using index 是理想状态;若写的是 Using where; Using filesort,说明 ORDER BY 没走索引

容易被忽略的一点:即使 EXPLAIN 显示用了索引,如果 rows 值接近全表行数,说明该索引选择性太差,可能还不如全表扫描——这时候得重新评估列顺序或是否真需要这个索引。

text=ZqhQzanResources