SQL tmp_table_size 的临时表内存阈值与磁盘切换监控

1次阅读

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

SQL tmp_table_size 的临时表内存阈值与磁盘切换监控

tmp_table_size 超了会直接写磁盘吗?

不会自动切换,MySQL 用的是“双阈值”机制:tmp_table_sizemax_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 PROFILECreating 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_TABLESDISK_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_tableTEMP_TABLES 行估算)反推合理值
  • 关键点:tmp_table_size 是软限制,不保证所有临时表都进内存;真正决定是否落盘的是执行引擎在构建过程中的实时判断

临时表行为高度依赖执行计划细节,同一 SQL 在不同数据分布下可能走完全不同的路径 —— 这比参数本身更难监控,也更容易被忽略。

text=ZqhQzanResources