索引不是越多越好,也不是“把 where 里的字段全塞进去”就结束。
这篇讲一个更实用的方法:从你的真实 SQL 反推索引。
先给一个可直接用的原则
设计复合索引时,按这个优先级排字段:
- 等值过滤字段(
=/IN) - 排序字段(
ORDER BY) - 范围字段(
><BETWEEN) - 返回列(用于覆盖索引,按需补)
一句话:先过滤,再排序,最后才是范围和覆盖。
一、先看业务 SQL,再谈索引
假设订单列表最常见 SQL:
SELECT id, user_id, status, create_time
FROM orders
WHERE user_id = 10086
AND status = 1
AND create_time >= '2026-03-01 00:00:00'
ORDER BY create_time DESC, id DESC
LIMIT 20;
从这条 SQL 反推:
user_id、status:等值过滤,放前面create_time、id:排序字段,接在后面
候选索引:
CREATE INDEX idx_orders_uid_status_ctime_id
ON orders(user_id, status, create_time DESC, id DESC);
二、为什么顺序这么重要
复合索引是按最左前缀匹配的,顺序错了,收益会掉很多。
比如你建成:
CREATE INDEX idx_bad ON orders(create_time, user_id, status);
那上面的 SQL 会先按 create_time 走,user_id/status 的过滤收益会被拖后,扫描行数往往更大。
三、3 个高频场景的索引模板
场景 1:列表查询(过滤 + 排序 + 分页)
SQL 特征:
WHERE a = ? AND b = ?ORDER BY c DESC, id DESCLIMIT ?
推荐:
INDEX(a, b, c DESC, id DESC)
场景 2:详情页查单条(精确定位)
SQL 特征:
WHERE biz_no = ?或WHERE tenant_id = ? AND biz_no = ?
推荐:
UNIQUE INDEX(tenant_id, biz_no)
能保证唯一性,也避免重复脏数据。
场景 3:统计报表(时间范围 + 分组)
SQL 特征:
WHERE tenant_id = ? AND create_time BETWEEN ? AND ?GROUP BY status
推荐起步:
INDEX(tenant_id, create_time, status)
报表类还要结合数据量评估是否做离线聚合,别把在线库当数仓打。
四、你最容易踩的 6 个坑
-
把低选择度字段放最前 比如
gender/status/is_deleted放第一列,过滤效果很弱。 -
只看 where,不看 order by 结果命中过滤却
Using filesort,耗时依然高。 -
索引过宽 字段太多会增大维护成本,写入变慢,内存占用更高。
-
重复索引
(a,b,c)已经存在,再建(a,b)往往是冗余。 -
把范围字段放太早 一旦前面进入范围匹配,后续列利用效率会下降。
-
以为覆盖索引永远最好 覆盖索引确实快,但也更重;高写入表要平衡读写成本。
五、我自己的落地流程(5 步)
- 先拉一周慢 SQL,按调用量和耗时排序
- 选 TOP 场景逐条
EXPLAIN,确认rows/key/extra - 给每个核心 SQL 设计 1 个主索引(而不是每条 SQL 一个索引)
- 灰度上线,观察慢日志和写入延迟
- 清理冗余索引,避免“索引越优化越慢”
六、一个“改前改后”例子
慢 SQL:
SELECT *
FROM orders
WHERE status = 1
AND user_id = 10086
ORDER BY create_time DESC
LIMIT 20;
问题:
SELECT *回表重- 索引顺序不合理,排序额外开销大
改造:
-- 索引
CREATE INDEX idx_orders_uid_status_ctime
ON orders(user_id, status, create_time DESC);
-- SQL
SELECT id, user_id, status, create_time
FROM orders
WHERE user_id = 10086
AND status = 1
ORDER BY create_time DESC
LIMIT 20;
通常你会看到:扫描行数下降、排序成本下降、P95 明显变稳。
最后总结
复合索引设计不是背口诀,而是把业务查询路径“翻译”成 B+Tree 顺序。
如果你只记一个句子,就记这个:
先拿慢 SQL,再反推索引;先服务高频场景,再追求理论完美。