宝塔面板MySQL深潜:用performance_schema+sys schema揪出“隐形”慢查询,自动推送到钉钉
痛点:slow_query_log 之外的盲区
很多运维在宝塔面板里只盯着 slow_query_log(慢查询日志),结果加索引、调参数后发现性能还是上不去。为啥?因为像 锁等待、I/O 瓶颈、临时表溢出磁盘 这类的“隐形”慢查询根本不会被 long_query_time 捕获。
轻云互联的云数据库实例默认启用 performance_schema 并预装了 sys schema,省去了底层开启的麻烦。本文要分享的是:如何借助这两个神器,在宝塔面板环境下实时揪出那些“隐藏”的性能杀手,并自动通知到钉钉。
一、在宝塔面板中确认/开启 performance_schema
登录宝塔面板 -> 数据库 -> 选择目标MySQL(5.7+),点击“性能调整” -> 检查 performance_schema=ON。如果没开,直接修改配置文件重启即可:
# 宝塔面板 MySQL 配置路径:/etc/my.cnf 或 /www/server/mysql/my.cnf
[mysqld]
performance_schema=ON
# 优化下默认表大小(避免过度消耗内存)
performance_schema_max_table_instances=10000
# 增加等待事件采集深度
performance-schema-instrument='wait/%=ON'
performance-schema-consumer-events-waits-current=ON
performance-schema-consumer-events-waits-history-long=ON
重启MySQL后,用 SHOW VARIABLES LIKE 'performance_schema'; 确认。
二、sys schema:开箱即用的性能分析视图
sys schema 是MySQL官方提供的性能分析视图集,无需手动构造复杂SQL。宝塔面板的MySQL 8.0默认自带,7.x需手动安装(SOURCE /usr/share/mysql/sys/sys_install.sql)。
2.1 找出等待事件最严重的 top 10 语句
直接查询 sys.statement_analysis 或 sys.host_summary_by_statement_latency,但更针对“隐形”慢的是等待事件:
-- 查看哪些等待事件累积时间最长(I/O、锁、CPU等)
SELECT * FROM sys.host_summary_by_wait_event
ORDER BY total_latency DESC
LIMIT 10;
这个视图能告诉你哪个主机、哪种等待事件(比如 wait/io/file/innodb/innodb_data_file)耗时最多。
2.2 揪出表级锁的元凶
很多慢查询是因为表锁(DDL)或行锁冲突导致。使用 sys.schema_table_lock_waits 查看:
SELECT * FROM sys.schema_table_lock_waits
WHERE waiting_pid IS NOT NULL\G
-- 如果返回空,说明当前无锁等待。可以看历史视图
SELECT * FROM sys.io_global_by_file_by_bytes
WHERE file LIKE '%.ibd'
ORDER BY total_io DESC
LIMIT 5;
2.3 快速定位临时表溢出磁盘
慢查询日志往往不记录这类“无索引”但数据量大的查询。利用 sys.statements_with_temp_tables:
-- 按磁盘临时表大小降序
SELECT * FROM sys.statements_with_temp_tables
ORDER BY disk_tmp_count DESC
LIMIT 10;
这个视图会直接列出造成磁盘临时表的SQL语句、执行次数、平均耗时,比翻slow log快多了。
三、自动采集并推送钉钉告警(宝塔面板计划任务 + API)
宝塔面板自带计划任务和 Shell 脚本执行能力。我们可以写一个脚本,定时(比如每5分钟)执行上述分析,如果发现异常数据就通过钉钉机器人发送消息。
3.1 宝塔 API 发送钉钉消息脚本
首先,在宝塔面板的“安全” -> “API接口” 中开启 第三方API,获取 key 和 secret。然后编写如下脚本 /www/server/scripts/mysql_health.sh:
#!/bin/bash
# 宝塔 API 地址
BT_KEY="你的BT_KEY"
BT_SECRET="你的BT_SECRET"
URL="https://你的服务器IP:8888/api?data="
# MySQL 连接参数(建议使用 socket 或 localhost,避免密码暴露)
MYSQL_CMD="mysql -uroot -p'你的密码' -S /tmp/mysql.sock -e"
# 1. 检测等待事件异常的线程数(超过 5 就触发告警)
WAIT_COUNT=$($MYSQL_CMD "SELECT COUNT(*) FROM events_waits_current WHERE EVENT_NAME LIKE 'wait/io/%' AND WAIT_TIME > 10000000;")
if [ "$WAIT_COUNT" -gt 5 ]; then
DETAIL=$($MYSQL_CMD "SELECT THREAD_ID, EVENT_NAME, SOURCE, WAIT_TIME/1000000000 AS 'wait_sec' FROM events_waits_current WHERE WAIT_TIME > 10000000 ORDER BY WAIT_TIME DESC LIMIT 5;" 2>/dev/null | column -t -s $'\t')
CONTENT="检测到I/O等待异常:当前等待线程数 $WAIT_COUNT\nTop 5 等待事件:\n$DETAIL"
fi
# 2. 检测是否存在表锁等待
LOCK_EXISTS=$($MYSQL_CMD "SELECT COUNT(*) FROM sys.schema_table_lock_waits WHERE waiting_pid IS NOT NULL;" 2>/dev/null)
if [ "$LOCK_EXISTS" -gt 0 ]; then
LOCK_DETAIL=$($MYSQL_CMD "SELECT * FROM sys.schema_table_lock_waits;" 2>/dev/null | column -t -s $'\t')
CONTENT="${CONTENT:+$CONTENT\n\n}检测到表锁等待:\n$LOCK_DETAIL"
fi
# 3. 如果有告警内容,发送钉钉
if [ -n "$CONTENT" ]; then
# 调用宝塔API → 钉钉群机器人(需要在钉钉创建机器人获取 webhook)
DINGTALK_URL="https://oapi.dingtalk.com/robot/send?access_token=你的钉钉TOKEN"
curl -s -X POST "$DINGTALK_URL" -H "Content-Type: application/json" -d "{\"msgtype\":\"text\",\"text\":{\"content\":\"$CONTENT\"}}"
fi
注意:避免在脚本里硬编码密码,推荐使用 .my.cnf 文件或 mysql_config_editor 加密存放。
3.2 在宝塔面板中添加周期性计划任务
- 进入宝塔面板 -> 计划任务 -> 添加任务
- 任务类型:Shell脚本
- 执行周期:每 5 分钟
- 脚本内容:直接写入上述脚本的路径,如
/bin/bash /www/server/scripts/mysql_health.sh &>/dev/null - 保存后立即生效。
四、实战案例:一条隐藏的“慢”SQL
某日接到告警:wait/io/file/innodb/innodb_data_file 等待次数飙升。使用 sys.statement_analysis 定位到是 SELECT COUNT(*) FROM big_table WHERE status = 'active'。该表行数千万,索引已建,但 count(*) 导致全索引扫描 + 大量页读取。添加 SELECT COUNT(id) FROM ...(改为覆盖索引)后,I/O等待直接降到 0。如果没有 performance_schema,这类问题可能拖到磁盘IO打满才被发现。
五、写在最后
宝塔面板的数据库管理很便捷,但默认只开启了 slow_query_log。本文的方法能让你像“CT扫描”一样钻入MySQL内部。轻云互联的云数据库实例从底层就调优了 performance_schema 采集粒度,配合宝塔面板的计划任务,可以极低成本实现企业级性能监控。试试把这段脚本跑起来,你会发现以前查不出的“玄学”慢查询瞬间浮出水面。