MySQL 慢查询排查手册:从 EXPLAIN 到索引优化的完整流程

MySQL Slow Query Debugging Handbook: From EXPLAIN to Index Optimization

| David | 2026-08-25T09:54:00

整理了一下我们团队排查 MySQL 慢查询的标准流程,从开启慢查询日志到 EXPLAIN 分析再到索引优化,希望能帮到有同样困扰的同学。

A comprehensive guide on our team's standard process for debugging MySQL slow queries, from slow query logs to EXPLAIN analysis and index optimization.

数据库慢查询是后端开发最常遇到的性能问题之一。我们团队踩了不少坑之后,总结了一套比较系统的排查流程,分享给大家。 第一步:找到慢查询 先开启 MySQL 的慢查询日志: SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 超过 1 秒的算慢查询 SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; 也可以用 pt-query-digest 分析慢查询日志,它会按照 SQL 模式聚合,告诉你哪类查询最耗时。 第二步:EXPLAIN 分析 找到慢 SQL 之后,用 EXPLAIN 看执行计划。重点关注这几列: type: 最好是 ref/eq_ref/const,如果是 ALL 就是全表扫描,必须优化 key: 实际用到的索引,NULL 表示没走索引 rows: 预估扫描行数,越少越好 Extra: 看有没有 Using filesort、Using temporary,这俩都是性能杀手 第三步:常见优化手段 添加合适的索引 最常见的就是缺索引导致全表扫描。但也不是索引越多越好,要注意: 联合索引要遵循最左前缀原则 WHERE 条件里用了函数的字段没法走索引,比如 WHERE DATE(create_time) = '2024-01-01' 应该改成范围查询 VARCHAR 类型的字段,如果值很长可以考虑前缀索引 SQL 改写 有些慢查询是 SQL 写法不合理导致的: 避免 SELECT *,只查需要的字段 子查询尽量改写成 JOIN LIMIT 大偏移量的分页用游标分页代替 OR 条件考虑拆成 UNION ALL 表结构优化 对于大表(千万级以上),可以考虑: 读写分离 按时间范围分区 冷热数据分离 适当冗余,减少 JOIN 一个实际案例 我们有个查询接口,执行时间从 3.2 秒优化到了 12 毫秒: -- 优化前:全表扫描 + 文件排序 SELECT * FROM orders WHERE user_id = 123 AND status = 1 ORDER BY created_at DESC LIMIT 10; -- EXPLAIN: type=ALL, rows=2000000 -- 优化后:添加联合索引 ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at DESC); -- EXPLAIN: type=ref, rows=15 就是加了一个合适的联合索引,查询时间直接从秒级降到了毫秒级。


Slow queries are one of the most common performance issues in backend development. Here's our team's systematic debugging process. Step 1: Find Slow Queries Enable MySQL slow query log and use pt-query-digest for analysis. Step 2: EXPLAIN Analysis Key columns to watch: type (avoid ALL), key (check index usage), rows (fewer is better), Extra (watch for filesort/temporary). Step 3: Common Optimizations Add appropriate indexes (follow leftmost prefix rule), rewrite SQL (avoid SELECT *, convert subqueries to JOINs, use cursor pagination), and optimize table structure for large tables. Real Case Optimized an order query from 3.2s to 12ms by adding a composite index on (user_id, status, created_at DESC).

← Back to News