什么时候该用多列索引而不是多个单列索引
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条件中,且值分布较均匀(如
order_no) 作为外键字段,需保证引用完整性(如
user_id在订单表中) 用于
ORDER BY col或
GROUP 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_at,
status变成表扫描过滤。
如何验证索引是否真的被用了
别猜,用
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值接近全表行数,说明该索引选择性太差,可能还不如全表扫描——这时候得重新评估列顺序或是否真需要这个索引。
