根本原因是内存上限截断、SQL触发强制落盘或tmpdir失控;必须同步校准tmp_table_size与max_heap_table_size、优化SQL写法、严格管控tmpdir路径。

根本原因不是“tmp table太多”,而是内存上限被截断、SQL写法触发强制落盘、或tmpdir路径本身已失控——三者任一没解决,调参只是把问题从磁盘搬到内存,甚至引发OOM。
tmp_table_size 和 max_heap_table_size 值不一致直接导致隐式降级
MySQL 创建内存临时表时,实际生效的是 min(tmp_table_size, max_heap_table_size)。很多运维只改了 tmp_table_size,却没动默认 16MB 的 max_heap_table_size,结果调到 512MB 也白费。
- 必须在
my.cnf的[mysqld]段里显式设为相等,例如:tmp_table_size = 256M和max_heap_table_size = 256M - 重启后立刻验证:
SHOW VARIABLES LIKE 'tmp_table_size';和SHOW VARIABLES LIKE 'max_heap_table_size';,两个值必须完全一致 - 混跑 OLTP + 报表的实例,建议按峰值报表 SQL 中间结果大小定值,但别超物理内存的 20%,否则
innodb_buffer_pool_size会被挤占
EXPLAIN 显示 Using temporary 就是明确信号,不是警告
只要 EXPLAIN 的 Extra 列出现 Using temporary,说明这条语句必然走临时表。如果还带 Using filesort,基本等于双重开销。
- 常见诱因:对
GROUP BY字段用函数(如GROUP BY DATE(created_at))、ORDER BY混合 ASC/DESC(MySQL 5.7 不支持)、JOIN后跨表GROUP BY - 修复不是加索引就完事:索引字段顺序必须严格匹配
GROUP BY或ORDER BY的列顺序,且不能含函数表达式 - 遇到
JSON_EXTRACT(col, '$.name')这类,考虑提前计算存为生成列(Generated Column),再建索引
tmpdir 路径配置失效比参数设错更隐蔽
哪怕 tmp_table_size 和 max_heap_table_size 都设对了,tmpdir 指向 /tmp 或 root 分区,照样会因空间不足或 IO 竞争报错。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 先查真实路径:
SELECT @@tmpdir;,再df -h看对应挂载点使用率;别信配置文件写了就生效 - 常见失效点:配置写在
[client]段、路径是符号链接、SELinux 未打标(chcon -t mysqld_tmp_t /path)、父目录权限不够(至少750) - 路径选型有硬约束:禁用 NFS、禁用
/tmp和/var/tmp、禁用/dev/shm(OOM 风险);首选独立 SSD 分区,如/mnt/ssd/mysql-tmp
Created_tmp_disk_tables 比值超过 10% 就该停下手头所有调参
这个指标不是“越高越差”,而是“突然跳变”才危险。它反映的是查询行为变化,不是容量瓶颈。
- 查当前值:
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';和Created_tmp_tables,算比值;持续 >10% 说明大量查询被迫落盘 - 对比调用前后:
SHOW STATUS LIKE 'Created_tmp%';在存储过程执行前后各跑一次,确认是不是它在造磁盘临时表 - 用
lsof +D /path/to/tmpdir排除非 MySQL 进程写大文件(比如备份脚本、日志轮转),避免误判
真正卡住人的从来不是单个参数怎么设,而是三个地方同时出问题:参数值不一致、SQL 还在用函数分组、tmpdir 指向的却是被其他服务共享的 /tmp 分区。任何一个漏掉,优化就只做了一半。










