组合索引字段顺序不能随便调,因mysql遵循最左前缀匹配规则,仅能从最左字段连续匹配;等值查询字段应前置,范围查询字段靠后,排序字段需与索引顺序一致以避免filesort。

组合索引字段顺序为什么不能随便调?
组合索引的字段顺序直接决定它能加速哪些查询,不是按“常用程度”排,而是按「最左前缀匹配」规则来——MySQL 只能从索引最左边开始连续匹配字段。
- 如果建了
INDEX (a, b, c),它能加速WHERE a = 1、WHERE a = 1 AND b = 2、WHERE a = 1 AND b = 2 AND c = 3,但对WHERE b = 2或WHERE c = 3完全无效 - 等值查询字段优先放前面(如
user_id = ?),范围查询字段(created_at > ?)尽量靠后,因为一旦遇到范围条件,后续字段就无法走索引了 - 排序字段(
ORDER BY)如果和索引顺序一致,还能避免Using filesort;反过来就会失效
什么时候该用组合索引,而不是多个单列索引?
单列索引在多条件查询中,MySQL 通常只能用上一个(除非是 index_merge,但代价高、不可控),而组合索引能真正覆盖多个过滤条件。
- 典型场景:
SELECT * FROM orders WHERE status = 'paid' AND user_id = 123 ORDER BY created_at DESC→ 建INDEX (status, user_id, created_at)比分别建三个单列索引高效得多 - 注意:如果已有单列索引
(a)和(a, b),MySQL 一般不会同时用它们;后者已包含前者能力,前者反而可能干扰优化器选择 - 联合索引长度不宜过长,尤其含
VARCHAR(255)字段时,建议加前缀长度(如name(50)),否则索引体积大、内存占用高、更新慢
执行计划里没走组合索引?先看这几个点
明明建了索引,EXPLAIN 却显示 type: ALL 或 key: NULL,大概率是这些原因。
- 查询中对索引字段用了函数或表达式:
WHERE YEAR(created_at) = 2024→ 改成WHERE created_at >= '2024-01-01' AND created_at - 隐式类型转换:
user_id是INT,但传了字符串'123',可能导致索引失效(尤其在严格模式下) - 统计信息过期:
ANALYZE TABLE orders强制更新表统计,有时优化器因旧数据误判索引价值 - 数据分布极端:比如
status只有 'draft'/'paid' 两种值,选择性太低,MySQL 可能直接放弃走索引
ALTER TABLE 加组合索引会影响线上服务吗?
会,但影响程度取决于 MySQL 版本和操作方式。5.6+ 支持 ALGORITHM=INPLACE 的 DDL,但并非所有情况都真正“在线”。
- 加索引本质是重建表(至少是重建索引树),期间会持有 MDL 写锁,阻塞写入;读请求不受影响,但若表大、IO 压力高,可能拖慢整体响应
- 务必在低峰期操作,提前用
pt-online-schema-change或gh-ost做无锁变更(尤其千万级以上表) -
CREATE INDEX语句比ALTER TABLE ADD INDEX更轻量,推荐用前者;且不要在事务里执行索引创建,避免长事务锁表
字段顺序、查询模式、执行计划验证、变更时机——这四点漏掉任何一环,组合索引就容易变成“看着很美,查着很慢”的摆设。










