← 返回首页

MySQL 索引优化实战:从慢查询到毫秒级

2026-05-10 · MySQL

问题背景

项目里有个查询订单列表的接口,数据量上来之后响应越来越慢。某天发现一个查询耗时超过 3 秒,用户已经反馈页面卡顿了。

SELECT * FROM orders
WHERE user_id = 12345
  AND status IN ('pending', 'processing')
  AND created_at > '2026-01-01'
ORDER BY created_at DESC
LIMIT 20;

第一步:EXPLAIN 看执行计划

在 SQL 前面加 EXPLAIN,发现 type=ALL,全表扫描。订单表已经 50 万行,难怪慢。

EXPLAIN SELECT * FROM orders
WHERE user_id = 12345
  AND status IN ('pending', 'processing')
  AND created_at > '2026-01-01'
ORDER BY created_at DESC
LIMIT 20;

-- type: ALL  rows: 523401  Extra: Using where; Using filesort

第二步:加联合索引

三个查询条件都参与了过滤,考虑建一个联合索引。把等值查询的列放前面,范围查询放后面:

ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);

再跑 EXPLAIN,type 变成了 rangerows 降到 156。执行时间从 3.2 秒降到 45ms。

第三步:覆盖索引进一步优化

虽然快了,还是有个 Using filesort。原因是 SELECT * 需要回表。如果只查需要的字段,可以用覆盖索引:

SELECT id, user_id, status, total_amount, created_at
FROM orders
WHERE user_id = 12345
  AND status IN ('pending', 'processing')
  AND created_at > '2026-01-01'
ORDER BY created_at DESC
LIMIT 20;

-- Extra: Using where; Using index
-- 执行时间:18ms

索引优化要点总结

  1. 先用 EXPLAIN 定位问题,看 type 和 rows
  2. 联合索引的列顺序很重要:等值在前,范围在后
  3. 尽量用 覆盖索引 避免回表
  4. 复合条件建联合索引,比多个单列索引效果好
  5. 不要在索引列上做函数运算,会导致索引失效
索引不是越多越好。每次写入都要维护索引,加之前一定要做收益评估。