ibtmp1暴增是配置缺失、残留未清、查询未优化三者叠加所致;仅改innodb_temp_data_file_path无效,必须设innodb_fast_shutdown=0后完整重启才能清理旧文件并生效上限。

直接结论:临时表空间暴增(ibtmp1持续增长)不是“用多了就该涨”,而是配置缺失 + 未清理残留 + 查询未优化三者叠加的结果。只调 innodb_temp_data_file_path 不关 innodb_fast_shutdown,重启后照样满。
为什么改了 innodb_temp_data_file_path 还没用
这个参数只控制「新实例启动时」的初始大小和上限,对已存在的 ibtmp1 文件完全无效。它像给新车设油箱上限,但车里已经灌满了油、还漏着——你得先停车、放空、再上路。
-
innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:5G是必要条件,不是充分条件 - 如果旧
ibtmp1已膨胀到 20G,MySQL 启动后仍会沿用它,不会自动截断或重建 - 必须配合
SET GLOBAL innodb_fast_shutdown = 0+ 完整重启,才能触发 InnoDB 清理临时段
删 ibtmp1 前必须做的三件事
直接删文件再启 MySQL 会报错甚至无法启动,因为 InnoDB 在 shutdown 过程中没完成 purge 和 insert buffer merge,残留的 undo/临时段元数据还在内存或日志里。
- 执行
SET GLOBAL innodb_fast_shutdown = 0(注意:需 SUPER 权限,且不能在只读实例上运行) - 确认所有长事务已结束:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; - 手动触发一次 flush:
FLUSH TABLES;(减少脏页残留)
哪些查询最容易把临时表打到磁盘
不是所有 GROUP BY 都危险,关键看是否能走索引+内存够不够。一旦临时表超过 tmp_table_size 和 max_heap_table_size 中的较小值,就会落盘——而磁盘临时表直接写进 ibtmp1。
-
GROUP BY字段无索引,或用了函数如GROUP BY DATE(create_time) -
ORDER BY非主键/非索引字段,且结果集大(EXPLAIN 显示Using filesort+Using temporary) -
DISTINCT配合多字段、大数据量,尤其含 TEXT/VARCHAR(2000+) 列 -
UNION(非UNION ALL)去重时无索引支撑
真正管用的组合操作
光改配置不碰 SQL,等于给超载卡车换轮胎却不卸货。线上环境建议按顺序执行:
- 先加监控:
SHOW GLOBAL STATUS LIKE 'Created_tmp%';看Created_tmp_disk_tables是否飙升 - 查问题 SQL:
SELECT * FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST_TEXT LIKE '%GROUP BY%' AND SUM_TIMER_WAIT > 1000000000000 ORDER BY SUM_TIMER_WAIT DESC LIMIT 5; - 对高频 SQL 加复合索引(比如
WHERE a=1 ORDER BY b,c就建(a,b,c)) - 最后才动配置:调小
tmp_table_size(比如 64M)逼出问题 SQL,再针对性优化,而不是盲目拉高到 1G
最常被忽略的一点:ibtmp1 占用的是连续磁盘空间,即使你设了 max:5G,一旦它曾涨到 15G 又缩回,文件本身不会自动收缩——必须删文件重启。别指望它自己“瘦身”。


















