events_statements_summary_by_digest无法查内存是因为其不记录内存事件,内存采集独立于sql执行统计,需通过memory_summary_by_thread_by_event_name等表结合线程id交叉分析。

直接查 events_statements_summary_by_digest 看不到内存分配细节——它只统计执行耗时、扫描行数等基础指标。语句级内存使用必须落到 memory_summary_by_thread_by_event_name 或 memory_summary_by_account_by_event_name,再结合线程/账户上下文反向关联 SQL。
为什么不能直接从 statements 表查内存?
events_statements_current 和 events_statements_summary_by_digest 表本身不记录内存事件。Performance Schema 的内存采集是独立维度:它按「内存事件名」(如 memory/sql/SELECT、memory/innodb/buf_pool)聚合,和 SQL 文本、digest、thread_id 是解耦的。你看到一条慢查询,但它的内存开销可能分散在多个事件里,比如解析阶段用 memory/sql/parse,排序阶段用 memory/sql/filesort,临时表用 memory/sql/TMP_TABLE。
所以必须走两条线交叉分析:
- 先从
events_statements_history或events_statements_current找出目标 SQL 对应的THREAD_ID - 再用该
THREAD_ID去memory_summary_by_thread_by_event_name查对应线程的内存事件明细
查语句级内存详情的实操步骤
假设你刚执行了一条 SELECT ... GROUP BY,想确认它是否触发了大量内存临时表或 filesort:
- 查当前线程 ID:
SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID = CONNECTION_ID(); - 查该线程最近的内存事件:
SELECT EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED, COUNT_ALLOC, COUNT_FREE FROM performance_schema.memory_summary_by_thread_by_event_name WHERE THREAD_ID = ? AND CURRENT_NUMBER_OF_BYTES_USED > 0 ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 5; - 重点关注这些事件名:
memory/sql/TMP_TABLE、memory/sql/filesort、memory/sql/JOIN_CACHE、memory/sql/SELECT - 如果想看全局趋势(比如哪个用户最吃内存),换成
memory_summary_by_user_by_event_name,过滤USER字段
setup_instruments 必须开启 memory/* 采集器
默认情况下,MySQL 5.7+ 虽然启用 performance_schema,但 memory/* 类事件是关闭的。不手动打开,所有内存表都为空:
- 检查状态:
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'memory/%' AND ENABLED = 'NO' LIMIT 3; - 临时开启(重启失效):
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'memory/%'; - 永久生效需加到配置文件:
performance-schema-instrument='memory/%=ON',然后重启 MySQL - 注意:开启后会有轻微性能开销,尤其高并发短连接场景,
CURRENT_NUMBER_OF_BYTES_USED是瞬时值,不是累计峰值
容易被忽略的内存事件粒度问题
同一个 SQL 可能触发多个内存事件,但它们不会自动归并到一条记录里。例如 GROUP BY 查询会同时写入 memory/sql/filesort 和 memory/sql/TMP_TABLE,而这两者在 memory_summary_by_thread_by_event_name 中是两条独立记录。你得自己加 SUM(CURRENT_NUMBER_OF_BYTES_USED) 才能估算总内存占用。
更关键的是:这些值只反映「当前未释放」的内存块。如果语句已结束,CURRENT_NUMBER_OF_BYTES_USED 很可能为 0,因为分配的内存已被释放。真正要抓活跃语句的内存快照,得在语句执行中(比如用 events_statements_current 查到 STATE = 'Sorting result' 时)立刻去查对应线程的内存表。











