数据库查询越来越慢别慌 这几款MySQL性能监控工具帮你快速定位问题
深夜十二点,监控报警群疯狂闪烁,你爬起来一看——生产库的慢查询告警已经堆了几十条。用户反馈页面卡成PPT,订单系统响应时间直接飙到三秒以上。这种场景,做过后端的朋友都懂,心脏骤停的感觉比喝冰美式还刺激。
别慌,MySQL出了问题,就像人生病了,得先做体检。今天咱们就聊聊那些能帮你快速”把脉”的MySQL监控工具,从入门到进阶,从免费到商业,总有一款适合你。
一、MySQL官方利器:Performance Schema
很多老运维朋友一提到性能分析,第一反应还是看慢查询日志。慢查询日志确实好使,但它有个致命弱点——它是事后诸葛亮。查询已经执行完了,你才去日志里翻记录,问题已经发生了,用户已经骂街了。
Performance Schema(性能架构)就不同了,它是MySQL 5.5开始引入的,专门设计用来做实时性能监控的。你可以把它理解成MySQL自带的体检仪,不用插管抽血,直接在体内就能监测各项指标。
怎么用它查实时数据
Performance Schema的数据都藏在几张核心表里,最常用的几张表你得先记住:
events_waits_summary_global_by_event_name:全局等待事件汇总,能看到哪类操作最耗时events_statements_summary_by_digest:SQL语句摘要,按执行的SQL模式聚合,方便找出问题语句sys.schema_total_latency:按表汇总的延迟数据,一眼看出哪张表拖慢了系统
下面这段SQL,是我在生产环境跑了很久的”万能问诊”脚本:
-- 查看耗时最长的SQL语句(按执行总时间排序)
SELECT
DIGEST_TEXT AS 语句模板,
COUNT_STAR AS 执行次数,
ROUND(SUM_TIMER_WAIT/1000000000000, 2) AS 总耗时秒,
ROUND(AVG_TIMER_WAIT/1000000000000, 2) AS 平均耗时秒,
ROUND(MAX_TIMER_WAIT/1000000000000, 2) AS 最大耗时秒,
ROUND(SUM_LOCK_TIME/1000000000000, 2) AS 总锁等待秒,
ROUND(SUM_ROWS_SENT) AS 返回行数,
ROUND(SUM_ROWS_EXAMINED) AS 扫描行数
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;
执行这段SQL之后,你会看到一张非常清晰的问题清单。如果某个SQL的SUM_ROWS_EXAMINED(扫描行数)远大于SUM_ROWS_SENT(返回行数),说明查询做了大量的全表扫描,索引大概率有问题。
实时追踪当前正在执行的语句
有时候问题不是历史数据能反映的,而是当前就有一个”坏人”在执行。这时候用sys库里的视图就非常方便:
-- 查看当前正在执行的语句,包括阻塞信息
SELECT
PROCESSLIST_ID AS 连接ID,
PROCESSLIST_USER AS 用户,
PROCESSLIST_HOST AS 来源,
LEFT(PROCESSLIST_INFO, 80) AS 当前语句,
PROCESSLIST_TIME AS 执行时长秒,
PROCESSLIST_STATE AS 状态,
ROW_LOCK_TIME AS 锁等待时间,
TX_ID AS 事务ID
FROM sys.x$processlist
WHERE PROCESSLIST_TIME > 3
ORDER BY PROCESSLIST_TIME DESC;
这个视图比直接查information_schema.processlist要好用得多,它整合了Performance Schema的数据,你能看到锁等待、事务ID这些关键信息,而不是只能看到一个SQL文本。
设置Performance Schema的开销问题
Performance Schema本身也有一些开销,虽然MySQL官方已经优化了很多,但在超高并发场景下还是需要注意。你可以通过以下方式控制开销:
-- 查看当前Performance Schema的开销配置
SELECT * FROM performance_schema.setup_instruments
WHERE NAME LIKE '%statement%' OR NAME LIKE '%wait%';
-- 可以关闭不需要的监控项来降低开销
UPDATE performance_schema.setup_instruments
SET ENABLED = 'NO', CONCATENSE = 'NO'
WHERE NAME LIKE '%wait/lock/mutex/%';
一般生产环境建议保留statement和wait两类instrument,其他类型的可以适当关闭。
二、MySQL自带的神器:mysqldumpslow + pt-query-digest
慢查询日志是MySQL的老朋友了,配置起来非常简单。在my.cnf里加上这几行:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
配置完重启MySQL(或者用SET GLOBAL动态修改),慢查询就开始记录了。
mysqldumpslow:官方分析工具
MySQL自带的mysqldumpslow工具可以解析慢查询日志。常用的用法:
# 按执行时间排序,显示前20条
mysqldumpslow -s t -t 20 /var/log/mysql/slow.log
# 按锁定时间排序
mysqldumpslow -s l -t 20 /var/log/mysql/slow.log
# 按返回行数排序
mysqldumpslow -s r -t 20 /var/log/mysql/slow.log
参数说明:-s是排序依据(t=时间、l=锁时间、r=返回行数、c=调用次数),-t是显示条数。
但说实话,mysqldumpslow的输出格式比较粗糙,对于复杂的SQL模式聚合能力有限。
pt-query-digest:Percona的杀手锏
这时候就需要请出Percona Toolkit里的pt-query-digest了。这是DBA圈子里公认的慢查询分析神器,没有之一。
# 分析慢查询日志,输出详细报告
pt-query-digest /var/log/mysql/slow.log
# 分析最近1小时的慢查询
pt-query-digest --since 1h /var/log/mysql/slow.log
# 生成HTML格式的报告,方便分享给团队
pt-query-digest --output=file --output-file=/tmp/slow_report.html /var/log/mysql/slow.log
执行之后,你会看到一份非常详尽的分析报告,包含:
- Top 10耗时查询:按执行时间、扫描行数、锁定时间等各种维度排序
- Query profile:每个查询的详细执行特征,比如平均耗时、p99耗时、执行频率
- File I/O分析:哪些查询造成了最多的磁盘读写
- Unique queries:去重后的SQL模式,方便发现真正的”问题模板”
报告里有个字段叫Query_time distribution,它会按照1秒以内、1-10秒、10秒以上等区间统计,一眼就能看出问题是集中在哪些延迟区间的。
还有一个非常实用的功能——实时分析慢查询:
# 实时监控慢查询日志,类似tail -f
pt-query-digest --review D=.,H=localhost --create-review-table /var/log/mysql/slow.log
这条命令会创建一个review表,把慢查询摘要存入表中,方便后续追踪同一类问题的变化趋势。
三、可视化强项:MySQL Workbench
如果你不喜欢命令行,MySQL官方提供的Workbench是个不错的选择。它的Performance tab提供了图形化的监控界面,能看到各种实时指标。
打开Workbench,连接到数据库后,点击顶部菜单的Server Status,或者直接打开Performance Dashboard,你会看到:
- 连接数趋势图
- 线程运行状态
- InnoDB缓冲池命中率
- 表锁等待情况
- 磁盘I/O统计
虽然不如专业监控工具那么强大,但对于日常排查来说,图形化界面确实比看日志直观得多。尤其是看到某个指标的曲线突然飙升,你能立刻感知到什么时候出了问题。
Workbench还有一个隐藏功能——慢查询日志分析。在Server Admin面板里,你可以直接配置慢查询日志的收集和分析,它会自动汇总并给出建议。
四、企业级监控:Prometheus + Grafana
对于大型团队来说,单纯靠日志分析已经不够了,需要一个集中式的监控平台。这时候Prometheus + Grafana的组合就成了标配。
部署Prometheus
首先需要一个Exporter来采集MySQL的指标。最常用的有两个选择:mysqld_exporter(官方)和mysql_exporter(社区)。
# prometheus.yml 配置示例
scrape_configs:
- job_name: 'mysql'
static_configs:
- targets: ['mysql-exporter:9104']
metrics_path: '/metrics'
params:
module: ['mysqld']
mysqld_exporter安装也很简单:
# 下载并启动mysqld_exporter
wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.14.0/mysqld_exporter-0.14.0.linux-amd64.tar.gz
tar xvf mysqld_exporter-0.14.0.linux-amd64.tar.gz
cd mysqld_exporter-0.14.0.linux-amd64
# 创建配置文件
cat > .my.cnf <<EOF
[client]
user=exporter
password=your_password
EOF
# 启动
./mysqld_exporter --config.my-cnf=.my.cnf
用Grafana看板看问题
导入Grafana官方提供的MySQL看板(ID: 7362),你会看到一张非常全面的监控面板。重点关注这几个指标:
- Queries per second:QPS趋势,异常飙升通常意味着某个查询变慢了
- Slow queries:慢查询数量,如果持续升高,说明有问题的SQL在增加
- InnoDB buffer pool hit rate:缓冲池命中率,低于95%就要警惕了
- Thread cache hit rate:线程缓存命中率,影响连接建立的开销
- Table locks waited:表锁等待次数,直接反映锁竞争情况
一个非常实用的告警规则配置:
# alert_rules.yml
groups:
- name: mysql
rules:
- alert: MysqlSlowQueriesHigh
expr: rate(mysql_global_status_slow_queries[5m]) > 10
for: 5m
labels:
severity: critical
annotations:
summary: "MySQL慢查询过高"
description: "过去5分钟慢查询速率超过10条/秒"
- alert: MysqlInnodbBufferPoolLow
expr: mysql_global_status Innodb_buffer_pool_read_requests /
(mysql_global_status Innodb_buffer_pool_reads + mysql_global_status Innodb_buffer_pool_read_requests) * 100 < 95
for: 10m
labels:
severity: warning
annotations:
summary: "InnoDB缓冲池命中率低"
这套组合拳打下来,你可以做到事前预警、事中定位、事后分析的完整闭环。
五、免费但强大的 pt-mysql-summary
最后推荐一个Percona Toolkit里非常实用的工具——pt-mysql-summary。它能在几秒钟内生成一份MySQL的”体检报告”,涵盖配置、状态、复制、性能等各个方面。
# 一键生成MySQL状态摘要
pt-mysql-summary --user=admin --password=xxx --host=localhost
# 输出到文件
pt-mysql-summary --user=admin --password=xxx --host=localhost > /tmp/mysql_health_$(date +%Y%m%d).txt
# 只检查配置,不做状态查询
pt-mysql-summary --ask-pass --host=localhost --config --no-status
执行后你会看到类似这样的输出:
=== MySQL Status ===
Uptime: 45 days 12:34:56
Threads Connected: 127
Questions since start: 1234567890
=== Key Configuration Items ===
innodb_buffer_pool_size = 8G
innodb_log_file_size = 2G
query_cache_type = OFF
max_connections = 500
slow_query_log = ON
=== Replication Status ===
Slave SQL Running: Yes
Slave IO Running: Yes
Seconds Behind Master: 0
=== Warnings ===
[WARNING] max_connections is too high (500), consider reducing to 200
[WARNING] innodb_buffer_pool_size may be too small for workload
这份报告最大的价值在于快速发现配置问题。很多慢查询问题不是代码写的烂,而是MySQL的默认配置就不适合生产环境。比如innodb_buffer_pool_size设置得太小,或者max_connections没有合理调整,这些在pt-mysql-summary的输出里都会被标红警告。
六、实战:一次完整的排查流程
理论讲完了,我们来模拟一个真实的排查场景。假设你现在收到了慢查询告警,QPS从平时的2000飙升到8000,响应时间从50ms涨到2s。
第一步:确认问题范围
# 用pt-mysql-summary快速查看全局状态
pt-mysql-summary --user=admin --password=xxx | head -100
确认是全部查询都慢了,还是特定查询慢了。如果是后者,进入第二步。
第二步:找出问题SQL
# 用pt-query-digest分析最近1小时的慢查询
pt-query-digest --since 1h /var/log/mysql/slow.log > /tmp/digest_$(date +%s).txt
# 查看Top问题
cat /tmp/digest_*.txt | grep -A 30 "Top 10"
你很快就能定位到是某几个特定的SQL模式拖慢了系统,比如某个大表的JOIN查询。
第三步:深入分析
-- 用Performance Schema查看这个SQL的实时执行情况
SELECT
DIGEST_TEXT,
COUNT_STAR,
ROUND(AVG_TIMER_WAIT/1000000000000, 2) AS avg_latency_sec,
ROUND(SUM_ROWS_EXAMINED) AS rows_examined
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT LIKE '%large_table%JOIN%'
ORDER BY SUM_TIMER_WAIT DESC;
发现这个查询每次执行要扫描500万行,但只需要返回几百行。典型的索引缺失或索引失效问题。
第四步:验证修复
-- 查看这个表的索引情况
SHOW INDEX FROM large_table;
-- 用EXPLAIN分析执行计划
EXPLAIN SELECT * FROM large_table WHERE status = 'active' AND create_time > '2024-01-01';
发现status和create_time两个字段没有联合索引,补充索引后重新执行,查询时间从2秒降到50毫秒。
第五步:持续监控
# 配置Prometheus告警,防止问题再次发生
# 在Grafana里添加面板,实时监控QPS和响应时间
这就是一个完整的排查闭环,从发现问题到定位问题到解决问题,全程不超过半小时。
写在最后
工具再强大,也替代不了排查问题的思路。上面这些工具就像是医生手里的听诊器、CT机、验血仪,用得好能药到病除,用不好也只是多了一套设备而已。
我的建议是:先用pt-mysql-summary和慢查询日志做初步诊断,再用pt-query-digest深入分析SQL,最后用Performance Schema和Prometheus做持续监控。这套组合拳打下来,大部分MySQL性能问题都能迎刃而解。
下次再遇到数据库变慢的情况,别再慌了,按这个流程走一遍,你也能成为同事眼中的”MySQL名医”。
