联合索引字段顺序必须按查询过滤强度从高到低排列,高频等值查询列(如user_id)须置最左,跳过中间列或范围查询后列将失效,覆盖索引仍需遵守最左前缀原则。

联合索引字段顺序必须按查询过滤强度从高到低排列
字段顺序不是随便写的,它直接决定索引能否被命中、能用上几列。MySQL的联合索引底层是B+树,数据按索引定义的列顺序物理排序:先排第一列,相同值再排第二列,以此类推。这意味着,只有高频、高区分度(即能快速筛掉大量行)的列放在最左,后续列才有机会被利用。
常见错误是把“看起来重要”的字段放前面,比如把 create_time 放在联合索引首位,但实际业务中 user_id 出现在 90% 的 WHERE 条件里,而时间范围只在报表场景才用——这时 user_id 必须前置。
- 优先选
=查询频率最高的列(如tenant_id、status、user_id) - 避免把
LIKE '%xxx'或低区分度字段(如gender、is_deleted)放最左 - 如果某列常用于范围查询(
BETWEEN、>),它后面的所有列都失效,所以尽量让它靠后
WHERE 条件中跳过中间列会导致右侧列完全失效
假设你建了索引 idx_user_status_created(user_id, status, created_at),那么 WHERE user_id = 123 AND created_at > '2026-01-01' 只能用上 user_id,created_at 不会走索引——因为 status 被跳过了,MySQL无法在B+树中定位到一个连续的 created_at 区间。
这个现象和优化器是否重排条件无关:即使你写成 WHERE created_at > '2026-01-01' AND user_id = 123,优化器会自动调整执行顺序,但依然无法绕过缺失 status 导致的断裂。
- 只要
status没出现在 WHERE 中,created_at就不可能命中索引 - 如果业务确实需要查
user_id + created_at,又不总带status,就得另建一个索引idx_user_created(user_id, created_at) - 不要指望一个联合索引覆盖所有排列组合;索引是为具体查询服务的,不是万能钥匙
范围查询之后的列永远无法使用索引
这是最容易被忽略的硬性限制。在 idx_a_b_c(a, b, c) 中,WHERE a = 1 AND b > 10 AND c = 100 只能用上 a 和 b,c 列索引失效。原因很直接:当 b 是范围条件时,对应子树里的 c 值不再有序,MySQL无法二分查找。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
注意,LIKE 'prefix%' 属于等值匹配的延伸,它不中断最左前缀;但 LIKE '%suffix' 或 LIKE '%mid%' 会让整个索引失效(连最左列都用不上)。
-
WHERE a = 1 AND b LIKE 'abc%' AND c = 5→a、b有效,c失效 -
WHERE a BETWEEN 1 AND 10 AND b = 2→ 只有a有效,b失效 - 若必须同时高效过滤
b和c,且a是范围条件,考虑把索引改为(b, c, a)或(c, b, a),前提是这些列在其他查询中也高频出现
覆盖索引能避免回表,但字段顺序仍受最左前缀约束
覆盖索引是指查询所需的所有字段都包含在索引中,比如 SELECT user_id, status FROM orders WHERE user_id = 123 AND status = 'paid',如果索引是 idx_user_status(user_id, status),就无需回主键索引查整行数据。这确实快,但别忘了:覆盖的前提仍是索引能被命中。
很多人以为“反正只查索引字段,顺序无所谓”,结果建了 idx_status_user(status, user_id),却发现 WHERE user_id = 123 完全不走索引——因为最左列是 status,而查询没提供它。
- 覆盖索引 ≠ 免除最左前缀规则;它只是额外收益,不能替代正确设计
- 如果查询既需要过滤、又需要返回,优先保证过滤字段满足最左前缀,再把 SELECT 字段追加到索引末尾
- 避免在索引末尾堆砌太多冗余字段,尤其是大字段(
TEXT、BLOB),会显著增大索引体积,拖慢写入
索引设计不是一次定终身的事。线上慢查询日志里反复出现的 WHERE 模式,才是你调整索引顺序最真实的依据;而 EXPLAIN 输出中的 key_len 和 Extra(尤其是 Using index 和 Using filesort)才是真正告诉你“它到底用了索引哪几列”的证据。










