MySQL 慢查询定位与索引优化的实战记录

订单表数据量过了千万级后,后台的一个统计查询开始明显变慢,最严重时耗时 3.2s。记录一下整个定位和优化的过程。

定位慢查询

先确认慢查询日志已开启:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;

抓到慢 SQL 后,用 EXPLAIN 看执行计划:

EXPLAIN SELECT ... FROM orders
WHERE user_id = 12345 AND status = 2
ORDER BY created_at DESC LIMIT 20;

发现问题

EXPLAIN 结果显示 type=ALL,走了全表扫描,rows 上千万。原来这条查询从来没用上索引。

建立联合索引

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

联合索引的列顺序很关键,要遵循「最左前缀」原则:等值条件放前面,范围/排序条件放后面。

进阶:覆盖索引

如果查询只用到了索引里的列,MySQL 就能直接从索引返回结果,不用回表:

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

这样 Extra 会显示 Using index,性能再上一个台阶。

结果

优化后该查询耗时从 3.2s 降到 80ms。更重要的是,CPU 负载也降下来了,因为不再有大量的全表扫描。

小结

索引优化的核心就三件事:看懂 EXPLAIN、遵循最左前缀、能用覆盖索引就用覆盖索引。