多个列分别建单列索引效果有限,mysql优化器通常只选其一;对and联合条件应优先建复合索引,遵循最左前缀匹配原则,并按等值条件、高选择性、范围条件顺序排列列。

多个列分别建单列索引有用吗
有用,但效果常被高估。MySQL 的 WHERE 条件中若同时用到 a = 1 AND b = 2,即使你为 a 和 b 各建了一个单列索引,优化器通常**只选其中一个**(比如选 a 索引查出所有 a = 1 的行,再回表过滤 b = 2),不会自动“合并”两个单列索引去加速联合条件。
常见错误现象:EXPLAIN 显示 key 列只出现一个索引名,rows 值远大于预期,查询慢。
- 单列索引适合各自独立的查询场景,比如
WHERE a = ?或WHERE b = ? - 对
AND联合条件,优先考虑复合索引,而非堆砌单列索引 - 5.6+ 版本支持
index merge(type: index_merge),但触发条件苛刻(如OR、范围 + 等值),且性能通常不如设计合理的复合索引
什么时候该用复合索引而不是多个单列索引
当查询条件频繁出现固定列组合,尤其是 AND 连接的等值匹配时,复合索引几乎总是更优。例如用户表常查 WHERE status = 'active' AND city = 'shanghai' AND created_at > '2024-01-01',那就该建 (status, city, created_at) 复合索引。
关键原则是「最左前缀匹配」:查询能用上索引的前提是条件从左到右连续覆盖索引列。比如索引是 (a, b, c):
-
WHERE a = 1 AND b = 2✅ 用上前两列 -
WHERE a = 1 AND c = 3❌c跳过了b,只能用到a -
WHERE b = 2 AND c = 3❌ 没有a,整个索引失效
注意:范围查询(>, , <code>BETWEEN)之后的列无法用于索引查找,仅可能用于排序或覆盖索引。例如 (a, b, c) 上执行 WHERE a = 1 AND b > 10 AND c = 5,c 不会加速查找,但若 select 只要 a,b,c,仍可能走覆盖索引避免回表。
单列索引和复合索引能共存吗?会不会冲突
可以共存,也不会冲突,但要考虑冗余和维护成本。例如已有复合索引 (a, b),再单独建 (a) 索引就是冗余——因为 (a, b) 已能完全替代 (a) 的功能。
但以下情况值得保留单列索引:
- 存在只查
b的高频查询,而(a, b)对WHERE b = ?无效 - 某列被大量用在
ORDER BY或GROUP BY中,且不总和前导列一起出现 - 主键是自增
id,但业务常按email查询,那email单列索引仍有必要
冗余索引会拖慢 INSERT/UPDATE/delete 性能,并占用更多磁盘和内存。可用 sys.schema_redundant_indexes 视图(MySQL 5.7+)或 pt-duplicate-key-checker 工具识别。
索引列顺序怎么排才合理
顺序不是随意的,核心看三类使用频率和选择性:
- 等值条件列优先:如
WHERE tenant_id = 123 AND status = 'paid',tenant_id通常区分度更高、且多租户场景下必带,放最左 - 高选择性列靠前:比如
gender(只有 ‘M’,’F’)选择性差,不应放复合索引最左;而user_id或order_no就很合适 - 范围条件列放最后:如
created_at > '2024-01-01'应放在复合索引末尾,否则它后面的列就失效了
一个典型反例:(created_at, user_id) 对 WHERE user_id = 1001 AND created_at > '2024-01-01' 效果很差,因为 created_at 是范围,user_id 实际用不上索引查找能力。应调换为 (user_id, created_at)。
实际设计时,别只盯着 WHERE,还要看 ORDER BY、GROUP BY 和是否能覆盖查询(即 SELECT 的字段是否全在索引里)。这些细节一旦漏掉,索引就容易建了却用不上。