本文目录导读:

分析SQL慢查询日志是数据库性能优化的核心环节,以下是系统化的分析方法和最佳实践(以MySQL为例,但思路通用):
开启并获取慢查询日志
确认是否开启
-- MySQL SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time'; -- 默认10秒 SHOW VARIABLES LIKE 'log_queries_not_using_indexes'; -- 是否记录无索引查询
临时开启(生产环境谨慎)
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; -- 单位秒,建议从2秒开始 SET GLOBAL log_queries_not_using_indexes = 'ON';
定位日志文件
SHOW VARIABLES LIKE 'slow_query_log_file'; -- 或查看MySQL配置文件my.cnf中的路径
使用mysqldumpslow工具分析(最常用)
# 按查询时间排序,显示前10条 mysqldumpslow -s t -t 10 /var/lib/mysql/hostname-slow.log # 按平均查询时间排序 mysqldumpslow -s at -t 20 /var/lib/mysql/hostname-slow.log # 按锁定时间排序 mysqldumpslow -s l -t 10 /var/lib/mysql/hostname-slow.log # 按查询次数排序(最频繁的慢查询) mysqldumpslow -s c -t 20 /var/lib/mysql/hostname-slow.log
参数说明:
-s:排序方式c(次数)t(时间)l(锁等待时间)at(平均时间)-t:显示前N条-g:正则过滤,-g "SELECT.*user"只显示包含user的查询
逐条分析慢SQL(核心步骤)
拿到慢SQL后,按以下顺序分析:
使用EXPLAIN分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 1\G
关键指标解读:
- type:访问类型(性能从好到差)
system/const:最优,主键或唯一索引查找eq_ref:联合查询,使用唯一索引ref:普通索引查找range:索引范围扫描(>、<、BETWEEN、IN)index:全索引扫描(比全表好一点)ALL:全表扫描(危险信号!需要添加索引)
- rows:预估扫描的行数(越小越好,10万行以上需警惕)
- Extra:重点关注
Using filesort:需要优化排序,考虑建立覆盖索引Using temporary:使用了临时表,需优化GROUP BY或DISTINCTUsing index:覆盖索引(好现象)Using where; Using index:理想情况,索引覆盖且条件过滤
检查索引使用情况
- 缺失索引:WHERE条件、JOIN字段、ORDER BY字段未加索引
- 索引失效:
- 对索引列使用了函数:
WHERE DATE(create_time) = '2024-01-01'→ 应改为WHERE create_time >= '...' AND create_time < '...' - 隐式类型转换:
WHERE user_id = '123'(如果user_id是数字类型) - 左模糊查询:
LIKE '%keyword'(不触发索引) - OR条件中存在非索引列
- 联合索引未满足最左前缀原则
- 对索引列使用了函数:
分析查询逻辑
- 返回不必要的数据:
SELECT *改为只选需要的列 - 分页偏移过大:
LIMIT 100000,20→ 考虑游标分页或子查询优化 - N+1查询问题:循环中查询数据库,改为JOIN或批量查询
- 嵌套子查询:尽量改为JOIN(MySQL对子查询优化有限)
高级分析工具
Performance Schema (MySQL 5.6+)
-- 查看最耗时的查询(无需慢日志) SELECT * FROM performance_schema.events_statements_summary_by_digest ORDER BY sum_timer_wait DESC LIMIT 10;
pt-query-digest (Percona Toolkit,强烈推荐)
# 安装后使用 pt-query-digest /var/lib/mysql/slow.log > analysis_report.txt # 实时分析(不写日志) pt-query-digest --processlist h=localhost,u=root,p=password
输出优势:
- 自动分组(归一化带参数的SQL)
- 给出时间分布、命中率、建议
- 找出“高频+慢”的重合SQL
第三方监控工具
- MySQL Enterprise Monitor(商业)
- Prometheus + Grafana + mysqld_exporter(开源)
- Datadog / SkyWalking(APM类)
典型慢SQL案例与优化
案例1:全表扫描
-- 原始SQL SELECT * FROM orders WHERE status = 1; -- 假设status有0/1两种值,数据量大 -- 分析 EXPLAIN输出type=ALL,rows=100万 -- 优化 1. 选择性高的字段才适合建索引(status选择性50%,不建议) 2. 若必须查询,考虑分区表(按时间分区)或加其他条件
案例2:分页偏移
-- 原始SQL SELECT id, name FROM users ORDER BY id LIMIT 100000, 20; -- 优化:游标分页 SELECT id, name FROM users WHERE id > 100000 ORDER BY id LIMIT 20; -- 或延迟关联 SELECT * FROM users INNER JOIN (SELECT id FROM users ORDER BY id LIMIT 100000, 20) AS tmp ON users.id = tmp.id;
案例3:GROUP BY + 排序
-- 原始SQL SELECT user_id, COUNT(*) FROM orders WHERE create_time > '2024-01-01' GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 10; -- 分析 EXPLAIN中出现Using temporary; Using filesort -- 优化 1. 索引:(create_time, user_id) 覆盖WHERE和GROUP BY 2. 如果数据量大,先查大范围再分组会更慢,可考虑物化视图
日常巡检的黄金规则
| 指标 | 健康值 | 警告值 | 危险值 |
|---|---|---|---|
| 慢查询数量(每小时) | < 10 | 10-100 | > 100 |
| 单条慢查询时间 | < 1秒 | 1-5秒 | > 5秒 |
| 全表扫描次数(每小时) | < 5 | 5-50 | > 50 |
| 索引命中率 | > 99% | 95-99% | < 95% |
生产环境注意事项
- 谨慎开启慢查询:
long_query_time初始设为2秒,防止日志过大 - 使用pt-query-digest自动分析:输出报告更易读
- 建立慢查询监控看板:Grafana + MySQL Exporter 实时展示
- 定期清理日志:慢查询日志可能迅速增长(设置
log_slow_admin_statements=OFF避免记录管理命令)
总结一句话:先看EXPLAIN的type和rows,再查是否用了索引,最后优化查询逻辑,大部分情况下,加对索引能解决80%的慢查询问题。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播