我有三个查询条件,组合索引怎么设计?顺序怎么定?
先说结论
组合索引字段顺序的核心原则:等值条件在前,范围条件在后,高区分度优先。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
组合索引设计是生产环境里最常做的优化操作。但很多人不知道字段顺序怎么定,随便排一个顺序,结果索引效果差很多。今天把组合索引设计的原则和实战经验讲清楚。
业务场景:订单查询的三个条件
-- 常见的订单查询
SELECT * FROM orders
WHERE status = 'paid' -- 等值条件
AND user_id = 12345 -- 等值条件
AND created_at > '2025-03-01' -- 范围条件
ORDER BY created_at DESC
LIMIT 20;
三个条件:status(等值)、user_id(等值)、created_at(范围)。索引怎么设计?
原则一:等值条件在前,范围条件在后
因为B+树索引是按字段顺序从左到右排序的。等值条件可以精确定位,范围条件只能确定一个范围。范围条件后面的字段无法使用索引。
-- ✖ 错误顺序:(created_at, status, user_id)
-- created_at是范围条件,放在最前,后面的status和user_id无法用索引
-- ✔ 正确顺序:(status, user_id, created_at)
-- status和user_id是等值,精确定位后,created_at的范围查询也能用上索引
ALTER TABLE orders ADD INDEX idx_s_u_c (status, user_id, created_at);
原则二:高区分度字段优先
区分度 = 该字段的不同值数量 / 总行数。区分度越高,过滤效果越好。
user_id的区分度远高于status(status可能只有5个值)。所以如果status和user_id都是等值条件,可以把user_id放前面:
-- 更优的顺序(user_id区分度更高)
ALTER TABLE orders ADD INDEX idx_u_s_c (user_id, status, created_at);
但实际中还要看查询模式。如果有些查询只带status不带user_id,那把status放前面更通用(最左前缀原则)。
原则三:考虑ORDER BY和覆盖索引
如果查询有ORDER BY created_at DESC,把created_at放在索引末尾,MySQL可以直接用索引排序,避免Using filesort。
如果SELECT的字段都在索引里,还可以做成覆盖索引,避免回表:
-- 覆盖索引:索引包含查询需要的所有字段
ALTER TABLE orders ADD INDEX idx_cover (status, user_id, created_at, order_id, amount);
-- EXPLAIN显示Using index,不需要回表
实战经验:不要加太多索引
索引不是越多越好。每个索引都会占用磁盘空间,而且写入时要维护所有索引。我的经验是:一张表的索引不超过5个,每个组合索引不超过5个字段。如果超过了,要重新审视是不是查询模式有问题。
总结
组合索引三原则:等值在前范围在后、高区分度优先、兼顾ORDER BY和覆盖索引。面试时能用一个真实的查询场景现场设计索引,并解释为什么这么排序,就很有说服力。
下一篇聊一个大数据开发经常遇到的场景:MySQL的Binlog是什么?它和大数据有什么关系?
你们生产环境的索引是怎么设计的?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长