mysql最左前缀原则怎么理解_mysql联合索引原理

来源:这里教程网 时间:2026-02-28 20:35:35 作者:

联合索引不是多个索引,而是一棵B+树

很多人误以为

CREATE INDEX idx_a_b_c ON t(a,b,c)
会生成
(a)
(a,b)
(a,b,c)
三棵树——其实不会。MySQL只建一棵B+树,排序规则是:先按
a
升序,
a
相同时再按
b
升序,
a
b
都相同时再按
c
升序。这就决定了查询必须“从左开始连续匹配”,否则无法定位到有序区间。

能用索引:
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c > 10
不能用索引:
WHERE b = 2
(跳过
a
)、
WHERE a = 1 AND c = 3
b
中断,
c
无法继续走索引)
注意:
WHERE b = 2 AND a = 1
看似顺序反了,但MySQL查询优化器会自动重排为
a = 1 AND b = 2
,仍可命中索引

范围查询(>、

这是最常踩的坑。一旦联合索引中某列用了范围条件,它右边所有列就**彻底失去索引加速能力**,哪怕你写了等值条件也不行。

SELECT * FROM orders WHERE user_id = 1001 AND status = 1 AND create_time > '2024-01-01';

这句只能用上

(user_id, status)
create_time
的范围判断之后,索引就“断”了——即使你后面还加了
AND pay_amount = 99.9
,这个
pay_amount
也查不到索引。

正确做法:把范围列尽量放在联合索引末尾,如
(user_id, status, create_time)
错误设计:若常用
WHERE status = 1 AND create_time BETWEEN ... AND ...
,却把
status
放在第二位,那这个查询根本用不上索引
LIKE 'abc%'
是范围行为,
LIKE '%abc'
则完全不走索引(连最左都不满足)

explain 是唯一能验证你是否真用上索引的工具

别靠“我写了 where a=1 and b=2”就以为索引生效了。必须看

EXPLAIN
key
key_len
字段:

key
显示实际使用的索引名 → 确认没走全表扫描
key_len
显示用了索引多少字节 → 比如
idx_user_status_time
user_id
是INT(4字节),
status
是TINYINT(1字节),那么
key_len = 5
表示只用到了前两列;若
key_len = 4
,说明只用到了
user_id
status
没参与索引查找
执行
EXPLAIN FORMAT=TRADITIONAL SELECT ...
,重点关注
type
(最好为
ref
range
),避免出现
ALL

索引字段顺序不是“哪个查得多就放前面”,而是按查询模式定

有人觉得“

status
取值少、区分度低,应该放后面”,但现实是:如果你的高频查询是
WHERE status = 'paid' AND user_id IN (1,2,3)
,那这个索引
(status, user_id)
就比
(user_id, status)
更合适——因为前者能直接定位到所有
status='paid'
的数据块,再在其中快速筛选
user_id
;后者却要先遍历每个
user_id
对应的索引项,再回表判断
status
,效率反而更低。

等值查询多、范围查询少 → 把高选择性(区分度高)字段放前面 固定前缀 + 范围查询 → 把等值列全放左,范围列放右,如
(shop_id, category_id, created_at)
存在多个高频查询组合?优先覆盖最耗性能的那条,或拆成两个索引(空间换时间)

真正容易被忽略的是:最左前缀原则不是“语法限制”,而是B+树物理结构决定的刚性约束。写SQL时字段顺序无关紧要,但索引定义的列序一旦定下,就锁死了所有可能的查询路径。改索引成本远高于改SQL,所以建之前就得想清楚主查询模式。

相关推荐