如何通过MySQL Performance Schema定位各查询的CPU占用占比
我太懂这种抓不到核心关联的挫败感了——明明开了通用日志、慢日志和Performance Schema,却还是没法把具体查询和CPU占用精准对应上对吧?别慌,咱们从Performance Schema的细节入手,这才是解决问题的核心路径,给你拆解几个关键操作:
很多时候不是开了Performance Schema就完事了,得确保对应的数据采集组件是激活的:
- 核心要开启
events_statements_current、events_statements_history、events_statements_history_long这几个语句事件表,它们会记录每个查询的CPU消耗细节。 - 先检查一下采集器状态,执行这条SQL:
SELECT NAME, ENABLED FROM performance_schema.setup_consumers WHERE NAME LIKE '%statements%';
如果结果里有NO的项,立刻用UPDATE开启:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE '%statements%';
performance_schema.events_statements_summary_by_digest是按语句摘要聚合的表,里面的SUM_TIMER_CPU就是这类查询累计消耗的CPU时间。你可以用它直接计算占比:
SELECT DIGEST_TEXT AS 查询语句摘要, ROUND(SUM_TIMER_CPU / 1000000000, 2) AS 累计CPU耗时_毫秒, ROUND((SUM_TIMER_CPU * 100) / (SELECT SUM(SUM_TIMER_CPU) FROM performance_schema.events_statements_summary_by_digest), 2) AS CPU占比_百分比, COUNT_STAR AS 执行次数 FROM performance_schema.events_statements_summary_by_digest WHERE SUM_TIMER_CPU > 0 ORDER BY CPU占比_百分比 DESC;
这个查询会把CPU耗时转成易读的毫秒,还算出了每个查询类别的CPU占比,按占比倒序排列——你会发现,很多时候高频执行的小查询(哪怕不是慢查询)才是CPU的头号消耗者。
如果遇到突发CPU飙高,想抓当前正在跑的查询的CPU占用,可以结合information_schema.processlist和events_statements_current:
SELECT p.id AS 线程ID, p.user AS 执行用户, p.db AS 数据库, e.DIGEST_TEXT AS 查询语句, ROUND(e.TIMER_CPU / 1000000000, 2) AS 当前CPU耗时_毫秒 FROM information_schema.processlist p JOIN performance_schema.events_statements_current e ON p.id = e.THREAD_ID WHERE p.command = 'Query' ORDER BY 当前CPU耗时_毫秒 DESC;
这个能帮你快速定位到当前正在吃CPU的查询,适合应急排查。
sys schema简化操作 MySQL 5.7及以上版本自带的sys schema封装了很多Performance Schema的实用查询,用起来更省心。比如x$statements_by_cpu直接按CPU消耗排序,能一眼看到占比最高的查询:
SELECT * FROM sys.x$statements_by_cpu;
带x$的是原始数值(未格式化),不带x$的是友好显示版本,你可以按需选择。
通用日志只记录"谁什么时候执行了什么",完全没有资源消耗数据;慢日志的Query_time是总执行时间,包含了IO等待、锁等待等非CPU耗时,没法精准反映CPU占用。只有Performance Schema的CPU定时器,才能给你纯CPU消耗的准确数据。
另外记得定期清理Performance Schema的统计数据(比如TRUNCATE TABLE performance_schema.events_statements_summary_by_digest;),不然旧的历史数据会干扰新的统计结果哦!
内容的提问来源于stack exchange,提问作者Shashank Singh

