因为mysql实际生效的内存临时表上限取tmp_table_size和max_heap_table_size二者较小值,若仅修改前者而后者仍为默认16mb,则超16mb的查询仍会强制落盘。

为什么只改 tmp_table_size 没用?
MySQL 实际生效的内存临时表上限,取 tmp_table_size 和 max_heap_table_size 二者中较小值。常见错误是:配置里写了 tmp_table_size = 256M,但 max_heap_table_size 还卡在默认的 16777216(即 16MB),结果所有超 16MB 的 GROUP BY 查询全被强制落盘——根本没机会用到你设的 256MB。
怎么确认两个参数是否真正同步?
别信配置文件写了就生效。必须进 MySQL 执行:
SELECT @@tmp_table_size, @@max_heap_table_size;
输出单位是字节,检查两值是否完全相等。同时查磁盘临时表生成频率:
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';
如果这个值每秒涨几十次,基本就是内存阈值被卡死了。注意:Created_tmp_disk_tables 持续增长 ≠ 一定参数没调好,也可能是查询本身含 TEXT 字段或缺失索引,这点后面会说。
安全设置两个参数的实操要点
- 必须在
/etc/my.cnf(或/etc/mysql/mysql.conf.d/mysqld.cnf)的[mysqld]段里**并列写两行**,不能只写一个,也不能用注释隔开 - 推荐用
M单位(如256M),别手算字节数——268435456容易写错,且难维护 - 值建议从
128M起步,上线前算余量:max_connections × 参数值 ≤ 总内存 × 20%;比如max_connections = 500,256MB × 500 ≈ 128GB,远超物理内存就危险 - 改完必须重启
mysqld;SET GLOBAL只对新连接生效,旧连接仍用旧值
调完还是走磁盘?先排查这几个硬限制
参数调对了,不代表查询就能进内存。以下情况无论内存多大,都会强制落盘:
-
SELECT里包含TEXT、BLOB或长VARCHAR字段 → MEMORY 引擎不支持,直接跳过内存阶段 -
GROUP BY或ORDER BY列无索引,且估算结果集宽度超限 → MySQL 会预判并提前落盘 - 用了
UNION、DISTINCT、子查询物化,中间结果字段太多或太宽 → 宽度计算方式和行数无关,单行超限就落盘 - MySQL 8.0.13+ 且
internal_tmp_mem_storage_engine = TempTable→ 此时受temp_table_max_ram控制,不是tmp_table_size
真正卡性能的往往不是参数值本身,而是查询是否能避免生成大临时表——加覆盖索引比盲目调高 tmp_table_size 更有效。参数只是兜底,不是解药。











