不能直接查到单个事务的内存占用,该表统计的是线程级内存事件累计用量,事务共享线程内存资源;需结合innodb_trx与threads表关联线程id,再查对应内存事件明细。

performance_schema.memory_summary_by_thread_by_event_name 能查到事务内存吗
不能直接看到“某个事务”占了多少内存,performance_schema.memory_summary_by_thread_by_event_name 统计的是线程级内存分配,而一个线程可能执行多个事务,事务本身不独占内存块,它用的内存来自线程的堆、语句解析缓冲、临时表、排序区等。所以你看到的是该线程在所有操作(含事务内/外)中各类内存事件的累计用量。
真正和事务强相关的内存消耗,往往体现在:
-
innodb_buffer_pool_pages_data—— 事务读取的数据页缓存在这里,但属于全局共享,无法归属到单个事务 - 临时表(
Created_tmp_tables,Created_tmp_disk_tables)—— 大事务中 GROUP BY / ORDER BY / DISTINCT 容易触发,这部分内存会记在对应线程的memory/innodb/buf_buf_pool或memory/sql/THD::main_mem_root下 - 锁结构(
lock_sys相关 event)—— 长事务持有大量行锁时,memory/innodb/lock_sys会上升,但这个值通常很小(KB 级)
如何定位高内存消耗的活跃事务
先找出正在运行且可能吃内存的事务,再结合线程 ID 去查内存明细:
- 用
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60找出运行超 1 分钟的事务 - 把结果里的
trx_mysql_thread_id拿出来,去查performance_schema.threads表匹配THREAD_ID,得到对应的PROCESSLIST_ID - 再用这个
PROCESSLIST_ID关联performance_schema.memory_summary_by_thread_by_event_name,筛选 top 几项内存 event
示例查询(一次连查):
SELECT t.PROCESSLIST_ID, trx.trx_started, trx.trx_state, m.EVENT_NAME, m.CURRENT_NUMBER_OF_BYTES_USED FROM information_schema.INNODB_TRX trx JOIN performance_schema.threads t ON trx.trx_mysql_thread_id = t.PROCESSLIST_ID JOIN performance_schema.memory_summary_by_thread_by_event_name m ON t.THREAD_ID = m.THREAD_ID WHERE m.CURRENT_NUMBER_OF_BYTES_USED > 1024*1024 -- 只看 >1MB 的项 ORDER BY m.CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10;
为什么开了 performance_schema 也看不到 memory 相关 event
因为默认情况下,Performance Schema 的内存 instruments 是关闭的。必须手动启用:
- 执行
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'memory/%'; - 该操作只对新创建的线程生效;已有线程的内存分配不会被补录
- 重启 MySQL 后设置会丢失,需写入配置文件:
performance-schema-instrument='memory/%=ON'加到my.cnf的[mysqld]段下 - 注意:开启后会有约 5–10% 的性能开销,生产环境建议仅在排查期启用
替代方案:从操作系统层面反推事务内存压力
当 Performance Schema 不可用或数据滞后时,更实际的做法是观察副作用:
- 用
SHOW FULL PROCESSLIST看State字段:长时间处于Sorting result、Creating sort index、Copying to tmp table的线程,大概率在用大量内存做中间计算 - 查
SHOW GLOBAL STATUS LIKE 'Created_tmp%':如果Created_tmp_disk_tables持续增长,说明 sort_buffer / tmp_table_size 不够,事务被迫写磁盘临时表 - 用
ps -o pid,comm,rss -C mysqld查 RSS,再结合SELECT THREAD_ID, PROCESSLIST_ID FROM performance_schema.threads对比线程数与内存增长趋势,判断是否某几个线程“吃掉”了大部分内存
真正难定位的,从来不是“哪个事务”,而是“哪类操作模式” —— 比如未加 LIMIT 的分页查询、没走索引的 JOIN、或者在事务里批量更新上万行。这些行为在 memory_summary_by_thread_by_event_name 里体现为 memory/sql/Query_cache 或 memory/sql/Filesort_buffer 的飙升,但根源得回溯到 SQL 本身。











