不会直接写磁盘,mysql采用“双阈值”机制:以tmp_table_size与max_heap_table_size的较小值为内存上限,超限且满足特定条件(如含blob/text、group by等)才退化为磁盘临时表。

tmp_table_size 超了会直接写磁盘吗?
不会自动切换,MySQL 用的是“双阈值”机制:tmp_table_size 和 max_heap_table_size 取较小值作为内存上限。只要临时表大小超过这个较小值,且语句没用到需要磁盘的特性(比如 BLOB/TEXT 列、GROUP BY 或 DISTINCT 的大结果集),才会退化为磁盘临时表(On_disk_tmp_tables 计数器+1)。
- 常见错误现象:
Created_tmp_disk_tables暴涨,但Created_tmp_tables并不高 —— 说明很多临时表一上来就绕过了内存阶段 - 使用场景:大 JOIN、未命中索引的 GROUP BY、ORDER BY + LIMIT 组合在无覆盖索引时容易触发
- 参数差异:
tmp_table_size是会话级变量,可动态设;max_heap_table_size同样会话级,但影响更广(还管 MEMORY 引擎表),两者必须同时调
怎么确认某条查询到底用了内存还是磁盘临时表?
不能只看慢日志或 EXPLAIN,得结合状态变量和实际执行路径。最可靠方式是开启 performance_schema 的临时表追踪,或用 SHOW PROFILE 看 Creating tmp table 阶段耗时是否伴随磁盘 I/O。
- 实操建议:对可疑 SQL 执行前先运行
FLUSH STATUS,再select ...,然后查SHOW STATUS LIKE 'Created_tmp%',对比增量 - 容易踩的坑:
Created_tmp_disk_tables是全局计数器,不是单条语句的快照;并发高时容易误判归属 - 性能影响:磁盘临时表默认用
MyISAM(8.0.16+ 可配internal_tmp_mem_storage_engine=TempTable),但一旦落盘,I/O 和锁开销明显上升
监控 tmp_table_size 是否频繁触发磁盘降级?
靠定期轮询 SHOW GLOBAL STATUS 效率低、颗粒度粗。推荐用 performance_schema.events_statements_summary_by_digest 查高频语句的 TEMP_TABLES 和 DISK_TEMP_TABLES 字段,再关联 sys.schema_table_statistics_with_buffer 看缓冲池内临时表行为。
- 使用场景:dba 日常巡检、告警规则配置(如每分钟
Created_tmp_disk_tables增量 > 50 触发告警) - 兼容性注意:MySQL 5.7 不支持
DISK_TEMP_TABLES统计字段,需降级用Created_tmp_disk_tables全局值 + 时间窗口差值估算 - 简短示例:
SELECT DIGEST_TEXT, COUNT_STAR, SUM_DISK_TEMP_TABLES FROM performance_schema.events_statements_summary_by_digest WHERE SUM_DISK_TEMP_TABLES > 0 ORDER BY SUM_DISK_TEMP_TABLES DESC LIMIT 5;
调大 tmp_table_size 就万事大吉?
不是。盲目调大会吃掉大量内存,尤其在连接数多、并发查询密集时,可能引发 OOM 或触发操作系统 swap,反而拖垮整体响应。真实瓶颈往往不在阈值本身,而在 SQL 写法或索引缺失。
- 容易踩的坑:把
tmp_table_size设成 1G,但实例总共才 4G 内存,200 个连接全开就占满 —— MySQL 不做连接间内存隔离 - 实操建议:优先优化 SQL(加索引、拆分 GROUP BY、避免 SELECT *),再按业务峰值连接数 × 平均临时表内存占用(可通过
performance_schema.table_io_waits_summary_by_table中TEMP_TABLES行估算)反推合理值 - 关键点:
tmp_table_size是软限制,不保证所有临时表都进内存;真正决定是否落盘的是执行引擎在构建过程中的实时判断
临时表行为高度依赖执行计划细节,同一 SQL 在不同数据分布下可能走完全不同的路径 —— 这比参数本身更难监控,也更容易被忽略。