虚拟机SQL监控要实时看慢查询,核心就两步:打开慢查询日志,盯紧实时会话和系统等待事件。 但虚拟机和物理机不一样,很多SQL在物理机上跑得飞快,到了虚拟机里就卡成蜗牛,问题往往不在SQL本身,而在虚拟化层抢资源。
虚拟机SQL监控和物理机有哪些区别?
很多人把物理机上的监控思路直接搬到虚拟机上,结果踩了坑,虚拟化层会引入CPU steal、内存超卖、磁盘IO排队等新问题,这些在物理机上根本不存在。
CPU steal是虚拟机独有的性能黑洞
当你用top命令看虚拟机CPU使用率时,会发现有个st字段,那就是CPU steal,简单说,就是宿主机把本该分给你的CPU时间抢走了,分给了其他虚拟机,如果这个值长期超过10%,你的SQL再优化也没用,因为CPU根本没在干你的活。
内存超卖导致数据库缓存频繁失效
虚拟机的内存是超卖分配的,宿主机内存不够时,会回收虚拟机内存,数据库的buffer pool被换出,命中率骤降,原本毫秒级的查询变成了秒级,物理机上你很少考虑这个问题,但在虚拟机上很常见。
磁盘IO竞争比物理机更剧烈
多个虚拟机共享同一块存储,一个虚拟机做全表扫描,其他虚拟机的IO等待时间立刻飙升,你在虚拟机上看到iowait很高,不一定是你自己的SQL引起的,可能是邻居在捣乱。
实时查看慢查询的三种主流方案
实时查看慢查询不能只看日志文件,因为日志是事后写的,等你看的时候问题可能已经过去了,真正实时的手段有三种,按效率从低到高排列。
开慢查询日志并动态刷新
MySQL和SQL Server都支持动态开启慢查询日志,MySQL里执行:
SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1;
把超过1秒的SQL记录下来,然后通过SHOW GLOBAL STATUS LIKE 'Slow_queries';查看当前累计的慢查询条数,这个方法能让你知道慢查询有没有在发生,但拿不到实时的SQL内容,想要实时抓取,还需要配合日志轮转和tail命令。
利用performance_schema和processlist实时抓取
这是真正意义上的“实时”,执行:
SELECT id, user, host, db, command, time, state, info FROM information_schema.processlist WHERE command != 'Sleep' AND time > 5;
这条命令直接列出当前执行时间超过5秒的会话,能看到具体的SQL文本和运行状态,如果某条SQL一直在Sending data或Copying to tmp table,瓶颈基本就锁定了,更精细的等待事件可以查performance_schema.events_waits_current,但要开启对应的采集器。
用监控工具自动采集慢查询
行业里常用的免费工具是Percona Monitoring and Management(PMM),支持MySQL、PostgreSQL、MongoDB,它直接读取performance_schema和慢查询日志,以图表形式展示每秒慢查询数量、平均查询耗时、锁等待时间等,如果不想装重量级工具,用Prometheus + mysqld_exporter也能达到类似效果,工具适合长期观察趋势,排查突发问题还是得靠processlist。
定位性能瓶颈的四个关键指标
慢查询日志只是告诉你哪条SQL慢,但没告诉你为什么慢,需要结合以下指标分析。
慢查询耗时构成
看慢查询日志里的Query_time、Lock_time、Rows_examined、Rows_sent,如果Lock_time占了大头,说明是锁等待;如果Rows_examined远大于Rows_sent,说明扫描了太多无用的行,缺索引。
会话等待事件
用SHOW ENGINE INNODB STATUS查看当前事务锁等待情况,重点看TRANSACTIONS段落,如果发现大量事务卡在LOCK WAIT,直接用sys.innodb_lock_waits视图查是谁堵住了谁,这种问题在OLTP系统里非常典型。
临时表与排序操作
在EXPLAIN执行计划里看到Using temporary或Using filesort,意味着SQL触发了临时表或文件排序,这类操作在虚拟机上尤其危险,因为临时表可能写到磁盘,加剧IO竞争,优化思路通常是改写SQL,减少排序字段,或者让索引直接覆盖排序。
连接数与线程池状态
看Threads_connected和Threads_running。Threads_running超过CPU核心数,说明SQL在排队执行,如果连接数不断上涨但活跃线程很少,可能是连接泄漏或慢查询堆积,此时优先杀掉长时间运行的会话,而不是盲目加连接数。
虚拟机特有性能陷阱排查
虚拟机性能瓶颈排查不能只看数据库内部,还得结合宿主机视角,下面三个检查项是必须做的。
检查CPU steal是否超标
执行top,观察st字段,如果持续大于10%,说明宿主机CPU超卖严重,处理方法是给虚拟机申请更多CPU份额,或者将数据库迁移到低负载宿主机,还有一个隐藏点:vmstat 1里的cs(上下文切换)异常升高,也可能是CPU steal引起的连锁反应。
内存膨胀与透明大页
虚拟机的内存膨胀(ballooning)会让数据库误以为内存充足,实际上内存被宿主机回收,运行free -h,如果available远小于free,且si、so有持续的swap换入换出,说明内存紧张,另一个常见的坑是透明大页(THP),MySQL官方明确建议关闭THP,否则会引发性能抖动,关闭命令:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
存储IO延迟突刺
用iostat -x 1看await和%util。await超过20毫秒,说明存储延迟偏高,注意%util接近100%不代表磁盘坏了,可能是多队列叠加,如果你的虚拟机和其他业务共享存储,建议把数据库数据文件迁移到独立的SSD卷,或者用nice调低备份任务的IO优先级。
从发现慢SQL到定位瓶颈的完整流程
结合以上知识,遇到慢查询不要慌,按下面五个步骤走。
- 开启实时会话抓取:执行processlist查询,把超过5秒的会话捞出来,记录SQL文本和
time字段。 - 抓取慢查询样本
:查看慢查询日志,找到同一条SQL的
Query_time和Rows_examined,确认是偶然慢还是持续慢。 - 分析执行计划:对SQL执行
EXPLAIN,看有没有全表扫描、临时表、filesort,同时用SHOW INDEX FROM 表名检查索引状态。 - 检查虚拟机资源:并行执行
top和iostat -x 1,观察CPU steal、iowait、await,这一步能快速区分是SQL问题还是资源问题。 - 针对性优化:如果是索引缺失就加索引;如果是锁竞争就优化事务隔离级别或拆分大事务;如果是CPU steal高,就只能迁移虚拟机。
这个流程跑一遍,80%的慢查询都能找到根源,剩下的20%,多半是应用层问题,比如连接池配置不合理、批量操作没走索引,需要结合应用日志继续排查。
虚拟机SQL慢查询常见问题解答
虚拟机里开启慢查询日志会不会影响数据库性能?
开启慢查询日志本身开销极小,几乎可以忽略,真正影响性能的是日志量过大,导致磁盘IO增加,建议设置long_query_time=1,不要全量记录。log_queries_not_using_indexes要谨慎开启,因为很多小表查询没走索引但速度很快,记录多了反而淹没有效信息。
为什么物理机上不慢的SQL,到了虚拟机就变慢?
最常见的原因是CPU steal或磁盘IO争抢,先看top的st%和iostat的await,如果这两个值都正常,再对比虚拟机和物理机的CPU频率、内存通道数量,还有可能是虚拟机配置的vCPU核心数少于物理机,导致并行度下降。
有没有免费的虚拟机SQL监控工具推荐?
Percona Monitoring and Management(PMM)完全免费,支持MySQL和PostgreSQL,安装简单,数据采集粒度可达秒级,也可以用Prometheus搭配mysqld_exporter自建监控体系,灵活度更高,如果是SQL Server,可以用开源的dbatools配合Performance Monitor计数器,效果也不错,免费工具在功能上不输商业版,只是需要自己维护。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/617398.html





