tmp_table_size 和 max_heap_table_size 必须设为相同值,因内存临时表大小取二者较小值;若不一致,调大 tmp_table_size 无效,易导致 created_tmp_disk_tables 持续增长。

tmp_table_size 和 max_heap_table_size 必须设成一样
MySQL 用内存临时表时,实际受两个参数共同限制:tmp_table_size 和 max_heap_table_size。它取两者中的较小值——哪怕你把 tmp_table_size 调到 256M,但 max_heap_table_size 还是默认的 16M,那临时表最多还是只能用 16M 内存。
- 线上环境务必让两者数值完全一致,否则调了也白调
- 修改后需重启 MySQL 或用
SET GLOBAL(注意权限和会话级影响) - 若只改
tmp_table_size,SHOW VARIABLES看起来生效了,但SHOW STATUS LIKE 'Created_tmp_disk_tables'依然居高不下,大概率就是被max_heap_table_size卡住了
查到“Using temporary”就该看执行计划,不是直接调参数
EXPLAIN 输出里出现 Using temporary,说明 MySQL 正在建临时表,但这不等于一定慢——关键看它是内存表还是磁盘表。真正伤性能的是落到磁盘的临时表(Created_tmp_disk_tables 持续增长)。
- 先确认是否真落到磁盘:监控
SHOW GLOBAL STATUS LIKE 'Created_tmp%',重点对比Created_tmp_tables和Created_tmp_disk_tables的比值 - 如果比值 > 20%,再考虑调参;如果
Created_tmp_disk_tables几乎为 0,调大tmp_table_size没意义 - 更有效的做法是优化 SQL:比如避免
SELECT DISTINCT配合无索引的ORDER BY,或把GROUP BY字段加上联合索引
tmp_table_size 不宜超过物理内存的 10%~15%
临时表内存不是“越多越好”。每个连接都可能分配一块这么大的内存空间,高并发下容易触发 OOM 或引发 swap。
- 假设服务器 64G 内存,
tmp_table_size = 1G看似合理,但如果并发连接数到 200,理论最大内存占用就达 200G - 建议从 64M 或 128M 起步,结合
Threads_connected和Created_tmp_disk_tables增长速率逐步上调 - Percona Server 或 MySQL 8.0+ 可配合
internal_tmp_mem_storage_engine = TEMPORARY(默认),确保内存表走 HASH 索引,比 MyISAM 内存表快不少
ORDER BY、GROUP BY、UNION 场景下临时表最容易撑爆
这三类操作是内存临时表的“主力消耗场景”,尤其当涉及大字段(TEXT、VARCHAR(2000))或未命中索引时,MySQL 很可能放弃内存表直接写磁盘。
-
GROUP BY如果字段没索引,且结果集行数多,优先加覆盖索引,比调tmp_table_size更治本 -
UNION默认去重,强制建临时表;如确定无重复,改用UNION ALL -
ORDER BY若含非索引字段,又没用LIMIT,极易触发大临时表;可考虑用子查询先LIMIT再排序
SELECT @@tmp_table_size, @@max_heap_table_size;,再看 Created_tmp_disk_tables 是否在业务高峰持续上涨——很多“性能问题”其实只是参数没对齐,或者压根没走到内存表这一步。











