慢SQL的问题如何排查?
慢 SQL 问题全面排查指南
慢 SQL 排查是一个系统性工程,需要结合数据库特性、执行计划和系统状态综合分析。以下是完整的排查流程和方法:
###一、快速定位慢 SQL
- 开启慢查询日志
-- MySQL (修改 my.cnf)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1-- 超过1秒的查询-- PostgreSQL
log_min_duration_statement = 1000-- 记录超过1秒的查询
- 实时监控工具
-- MySQL
SHOW FULL PROCESSLIST;-- 查看当前运行查询-- PostgreSQL
SELECT * FROM pg_stat_activity WHERE state = 'active';
- 性能分析工具
- Percona Toolkit
pt-query-digest(分析慢日志) - MySQL Workbench Performance Dashboard
- pgBadger (PostgreSQL 日志分析器)
###🔍 二、SQL 执行计划分析
EXPLAIN 是核心诊断工具:
-- MySQL
EXPLAIN FORMAT=JSON
SELECT * FROM orders WHERE user_id = 100;-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE user_id = 100;
执行计划关键关注点:
graph TD
A[执行计划] --> B[全表扫描?]
A --> C[索引使用情况]
A --> D[排序/临时表]
A --> E[嵌套循环连接]
A --> F[预估/实际行数偏差]
- 全表扫描 (Seq Scan)
- 现象:
type=ALL(MySQL),Seq Scan(PG) - 解决方案:添加合适索引
- 索引失效
- 常见原因:
- 隐式类型转换:
WHERE varchar_col = 123 - 函数操作:
WHERE DATE(created_at) = '2023-01-01' - 前导通配符:
WHERE name LIKE '%abc'
- 排序和临时表
Using filesort(MySQL) /Sort(PG)- 解决方案:为 ORDER BY/GROUP BY 添加索引
###📊 三、索引优化策略
- 最佳索引设计
- 最左前缀原则:
INDEX (col1, col2, col3) - 覆盖索引:包含所有查询字段
- 索引选择性:高基数字段优先
- 缺失索引检测
-- MySQL
SELECT * FROM sys.schema_unused_indexes;-- PostgreSQL
SELECT * FROM pg_stat_all_indexes
WHERE idx_scan = 0;
- 索引问题诊断
- 冗余索引:
pt-duplicate-key-checker - 碎片整理:
OPTIMIZE TABLE/REINDEX
###⚙️ 四、SQL 语句优化
- 分页优化
-- 传统分页(慢)
SELECT * FROM orders ORDER BY id LIMIT 100000, 10;-- 优化方案
SELECT * FROM orders
WHERE id > 100000 ORDER BY id LIMIT 10;-- 基于游标
- **避免 SELECT ***
-- 优化前
SELECT * FROM users WHERE ...;-- 优化后
SELECT id, name, email FROM users WHERE ...;
- JOIN 优化
- 小表驱动大表
- 避免笛卡尔积
- 使用 EXISTS 代替 IN
###📈 五、数据库系统级优化
- 关键参数调整
# MySQL (innodb)
innodb_buffer_pool_size = 70% RAM
innodb_log_file_size = 1-2GB
innodb_flush_log_at_trx_commit = 2# PostgreSQL
shared_buffers = 25% RAM
work_mem = 4-32MB
effective_cache_size = 50-75% RAM
- 统计信息更新
-- MySQL
ANALYZE TABLE orders;-- PostgreSQL
ANALYZE orders;
###🔧 六、架构级解决方案
- 读写分离
- 分库分表
- 水平分片:按 user_id 分片
- 垂直拆分:分离热点字段
- 缓存策略
- 查询缓存:Redis/Memcached
- 二级缓存:Hibernate Caffeine
###七、诊断工具链
| 工具类型 | MySQL 工具 | PostgreSQL 工具 |
|---|---|---|
| 实时监控 | mytop, innotop | pg_top, pg_activity |
| 性能分析 | EXPLAIN ANALYZE | EXPLAIN (ANALYZE, BUFFERS) |
| 压力测试 | sysbench, mysqlslap | pgbench |
| 日志分析 | pt-query-digest | pgBadger |
| 指标收集 | Prometheus + MySQL Exporter | Prometheus + pgExporter |
###🔄 八、优化流程闭环
graph LR
A[发现慢SQL] --> B[执行计划分析]
B --> C{索引问题?}
C -->|是| D[优化索引]
C -->|否| E{SQL写法问题?}
E -->|是| F[重写SQL]
E -->|否| G{系统资源瓶颈?}
G -->|是| H[参数调优/扩容]
G -->|否| I{数据量过大?}
I -->|是| J[分库分表]
I -->|否| K[架构优化]
D --> L[验证效果]
F --> L
H --> L
J --> L
K --> L
L --> M[监控持续改进]
###🚨 九、常见慢 SQL 模式及解决方案
| 问题模式 | 解决方案 |
|---|---|
| N+1 查询问题 | 批量查询 / JOIN 替代 |
| 大偏移量分页 | 游标分页 / 基于ID分页 |
| 全表更新 | 分批更新 / CTE 优化 |
| 锁竞争激烈 | 降低事务隔离级别 / 乐观锁 |
| 统计信息过时 | 定期 ANALYZE / 自动统计更新 |
| 未使用参数化查询 | 启用 prepared statements |
###💡 十、高级技巧
- 执行计划可视化
- MySQL Workbench Visual Explain
- https://explain.dalibo.com (PG)
- SQL 重写器
-- 优化前
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);-- 优化后
SELECT u.* FROM users u
JOIN orders o ON u.id = o.user_id;
- 隐藏性能杀手排查
-- 检查触发器/存储过程
SHOW TRIGGERS;
SELECT * FROM information_schema.ROUTINES;
通过以上系统化排查流程,90%以上的慢 SQL 问题都能得到有效解决。关键要点:先分析执行计划,再优化索引,最后考虑架构调整,同时建立持续监控机制预防问题复发。
