复合索引更可靠,因mysql无法自动高效拼接多个单列索引处理多条件where,而复合索引遵循最左前缀原则,能精准覆盖等值+范围查询,避免index_merge或全表扫描。

复合索引为什么比多个单列索引更可靠
MySQL 对多列 WHERE 条件(如 status = 1 AND type = 'user' AND created_at > '2024-01-01')不会自动“拼接”多个单列索引去高效筛选,哪怕每列都有索引。它可能走全表扫描(EXPLAIN 显示 type=ALL 或 key=NULL),也可能退而求其次用 index_merge——但这不是优化,是兜底:要读多次索引、做内存交集、常触发临时表,性能差且不稳。
真正可控的解法是建一个覆盖全部条件的复合索引,比如:CREATE INDEX idx_status_type_created ON table_name (status, type, created_at);
- 索引按查询中实际出现的列顺序定义,不是按表结构顺序
- 等值条件列(
=、IN)放左,范围条件列(>、BETWEEN)放右——因为范围之后的列无法用于WHERE过滤(但可用于ORDER BY) - 高频、高区分度的列优先靠左,比如
user_id比status更适合作为第一列
哪些查询能真正用上复合索引的全部列
能否用满索引,取决于条件是否满足「最左前缀」且未被中断。假设索引是 (a, b, c):
- ✅
WHERE a = 1 AND b = 2 AND c = 3:三列全命中 - ✅
WHERE a = 1 AND b > 10 ORDER BY c:a和b用于过滤,c用于排序(b是范围,c不参与WHERE但可排序) - ❌
WHERE b = 2 AND c = 3:跳过a,索引失效 - ❌
WHERE a = 1 AND c = 3:b缺失,c无法使用 - ⚠️
WHERE a IN (1,2,3) AND b = 5:a是等值列表,仍算最左匹配,b可继续生效
用 EXPLAIN 看 key 是否是你建的索引名、rows 是否明显下降,是最直接验证方式。
什么时候该放弃复合索引,改回单列索引
不是所有多条件场景都适合一个复合索引。以下情况建议分建单列索引:
- 查询模式高度不固定:有时查
city,有时查age,偶尔才同时查两者——两个单列索引比一个(city, age)更灵活 - 某列选择性极低(如
is_deleted TINYINT只有 0/1),又常单独查询,单独建索引比把它塞进复合索引左侧更有效 - 存在大量
OR条件,例如WHERE a = 1 OR b = 2,这时index_merge_union可能真被启用,单列索引反而更合适(但优先考虑改写为UNION)
注意:多个单列索引在 AND 查询中通常只用一个,其余列过滤靠回表或内存扫描,性能上限天然低于设计得当的复合索引。
容易被忽略的隐性失效点
即使索引结构和查询条件看起来严丝合缝,也可能因这些细节失效:
- 在索引列上用了函数:
WHERE YEAR(created_at) = 2024→ 改成created_at BETWEEN '2024-01-01' AND '2024-12-31' - 隐式类型转换:
WHERE user_id = '123'(user_id是INT)→ 字符串强制转数字,可能丢索引 - 使用了
!=、NOT IN、LIKE '%abc':这些操作直接让后续索引列失效 - 字段字符集或排序规则不一致:比如关联字段一边是
utf8mb4_unicode_ci,另一边是utf8mb4_general_ci,JOIN 或 WHERE 可能无法走索引
最稳妥的做法是:每次加完索引,用真实参数跑一遍 EXPLAIN FORMAT=JSON,重点看 "using_index_merge": true 是否出现、"rows" 是否远超预期——如果有,说明你还没真正控制住执行路径。











