临时表是否落盘由tmp_table_size与max_heap_table_size的较小值决定,且受字段类型、索引覆盖等影响;仅当二者均足够且无TEXT/BLOB等不支持类型时才使用内存临时表。

临时表是内存还是磁盘,由 tmp_table_size 和 max_heap_table_size 共同决定
MySQL 不是“先试内存、不行再落盘”,而是**同时受两个参数限制**:只要临时表预计大小超过其中任意一个,就会直接创建磁盘临时表。很多人只调 tmp_table_size,忘了 max_heap_table_size 必须同步调大,否则无效。
实操建议:
-
tmp_table_size控制服务器层对单个内部临时表的内存上限(仅对 MEMORY 引擎生效) -
max_heap_table_size是 HEAP 表(即 MEMORY 引擎)单表最大允许大小,临时表也遵守这个限制 - 两者取较小值作为实际阈值,例如设了
tmp_table_size=256M但max_heap_table_size=16M,那超 16M 就强制落盘 - 查看当前会话实际生效值:
SELECT @@tmp_table_size, @@max_heap_table_size;
怎么确认某条 SQL 用了磁盘临时表
不能只看 EXPLAIN 的 Extra 字段是否含 “Using temporary”——它只表示用了临时表,不区分内存还是磁盘。真正判断依据是 SHOW STATUS LIKE 'Created_tmp%'; 中的增量变化。
实操建议:
- 执行前先记录:
SHOW STATUS LIKE 'Created_tmp%'; - 跑完 SQL 再查一次,重点关注
Created_tmp_disk_tables是否增加(说明用了磁盘临时表) -
Created_tmp_tables是总次数,包含内存和磁盘;差值才是磁盘表数量 - 如果
Created_tmp_disk_tables / Created_tmp_tables > 0.1,说明有明显比例的临时表被强制落盘,值得优化
哪些操作容易触发磁盘临时表
不是所有 GROUP BY 或 ORDER BY 都会建临时表,也不是所有临时表都会落盘。关键在字段类型、索引覆盖、排序量和结果集大小。
常见踩坑场景:
- 对
TEXT/BLOB字段做GROUP BY或ORDER BY:即使数据很短,也会直接走磁盘临时表(MEMORY 引擎不支持这些类型) - 联合索引无法覆盖
SELECT所有字段 +ORDER BY,导致需要回表并生成临时表排序,且字段多、行长时极易超限 -
UNION结果集字段类型不一致(如一边是VARCHAR(100),一边是VARCHAR(200)),MySQL 会按宽的对齐,临时表宽度翻倍 - 使用
SQL_SMALL_RESULT提示也不保证内存表——它只是告诉优化器“结果集小”,但最终仍受两个 size 参数约束
临时表生命周期与调试技巧
临时表只在当前 session 存在,断开连接就销毁。但调试时你没法直接 DESCRIBE 它,因为名字是内部生成的(如 sql_<hex></hex>),且不暴露在 information_schema 中。
实用方法:
- 开启
performance_schema并查询:SELECT * FROM performance_schema.events_statements_history WHERE SQL_TEXT LIKE '%your_sql%';,看TEMP_TABLES列 - 用
SET SESSION debug='+d,info,tmp_table';(需编译时带 debug 支持),会在错误日志里输出临时表类型和大小估算 - 在慢查询日志中开启
log_queries_not_using_indexes并配合long_query_time=0,结合Created_tmp_disk_tables增量定位问题 SQL - 注意:
CREATE TEMPORARY TABLE是用户显式创建的,和优化器自动建的“内部临时表”完全无关,别混淆
临时表是否落盘,从来不是黑盒行为——它严格取决于字段类型、索引设计、参数配置三者的交集。最容易被忽略的是 max_heap_table_size 这个“隐形天花板”,调参时漏掉它,等于白调。


















