应重点关注Created_tmp_disk_tables与Created_tmp_tables的比值,超5%需干预,超15%表明SQL或参数严重失衡;同时检查temptable_max_ram是否被默认值限制,并通过memory_summary_by_thread_by_event_name定位高内存消耗SQL。

查Created_tmp_disk_tables比值,别只看绝对数
临时表落盘不是“有没有”,而是“比例高不高”。Created_tmp_disk_tables单看数字容易误判——比如值是1200,但Created_tmp_tables是2000,比值60%就严重超标;如果后者是10万,比值1.2%其实很健康。
必须算比值:SELECT VARIABLE_VALUE AS disk_tmp FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_disk_tables';SELECT VARIABLE_VALUE AS total_tmp FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Created_tmp_tables';
比值 >5% 就该干预,>15% 说明 SQL 或参数已明显失衡。
- 这个比值只对新连接生效,老连接沿用启动时的
max_heap_table_size和internal_tmp_mem_storage_engine设置,调参后要等10–30分钟再观察 - 别查
tmp_table_size——MySQL 8.0 已彻底移除该参数,查不到、设不了、配置里留着也无效
确认temptable_max_ram是否被默认值卡死
MySQL 8.0.16+ 默认启用TEMPTABLE引擎,但它不认max_heap_table_size,而靠独立参数temptable_max_ram控制总内存池。默认值是物理内存的3%(上限4 GiB),64 GiB机器就只有约2 GiB——一个带JSON解析的GROUP BY轻松突破,立刻写入ibtmp1。
-
SELECT @@temptable_max_ram;查当前值(单位字节),若返回2147483648就是2 GiB - 该参数不支持
SET GLOBAL,必须写进my.cnf的[mysqld]段:temptable_max_ram = 4G(MySQL 8.0.23+ 支持单位缩写,旧版请写4294967296) - 别超物理内存15%,否则可能触发系统OOM;重启前务必执行
SET GLOBAL innodb_fast_shutdown = 0;再SHUTDOWN;,确保旧ibtmp1可被安全重建
用memory_summary_by_thread_by_event_name定位肇事SQL
很多“TempTable吃内存”其实是单个连接在扛锅。比如某报表查询生成了3 GB中间结果,全塞进memory/temptable/physical_ram,而其他连接安静如鸡。
- 先查高内存线程:
SELECT THREAD_ID, USER, HOST, EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED FROM performance_schema.memory_summary_by_thread_by_event_name WHERE EVENT_NAME LIKE 'memory/temptable/%' ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 5; - 拿到
THREAD_ID后,关联查SQL:SELECT PROCESSLIST_INFO FROM performance_schema.processlist WHERE ID = ?; - 重点盯
EXPLAIN里出现Using temporary且没走索引的语句——GROUP BY字段缺失最左前缀、用UPPER(name)或JSON_EXTRACT(col, '$.field')分组、选了TEXT字段又ORDER BY,都会强制建大临时表
别忽略memory/sql/thd堆积带来的隐性开销
每个连接都带着sort_buffer_size、read_buffer_size等线程级buffer,哪怕空闲也占内存。memory/sql/thd持续高位,往往不是SQL问题,而是应用连接池没配好——几百个长连接堆着,RSS就无声涨上去。
- 查连接分布:
SELECT USER, HOST, COUNT(*) AS conn_count FROM performance_schema.threads WHERE TYPE = 'FOREGROUND' GROUP BY USER, HOST ORDER BY conn_count DESC; - 对比
Threads_connected和Threads_running:如果前者远大于后者(比如500 vs 5),大概率是连接泄漏或空闲连接未回收 -
max_connections别盲目设高,按峰值×1.5预留即可;配合应用端设置maxIdleTime或testWhileIdle,避免连接长期闲置
temptable_max_ram和max_heap_table_size两个参数的错位,以及SQL里那些看似无害却强制落盘的表达式——它们不会报错,只会默默把ibtmp1撑爆。


















