tmpdir配置不当是olap查询慢的首要瓶颈,常见失效原因包括配置文件覆盖、符号链接被拒、权限不足、selinux未打标、段落错误;应设于独立ssd/nvme分区,禁用nfs、root分区及/tmp,并与innodb_temp_data_file_path物理隔离。

tmpdir 路径设不对,再大的内存缓冲也救不了磁盘临时表的性能问题。 它不是“锦上添花”的配置项,而是 OLAP 查询、大 GROUP BY 或复杂 JOIN 出现慢查询时,第一个该查、也最容易被忽略的瓶颈点。
tmpdir 配置后不生效的常见原因
改完 my.cnf 重启却还是看到 SHOW VARIABLES LIKE 'tmpdir' 返回 /tmp 或空值,大概率是以下情况之一:
- MySQL 加载了多个配置文件(比如
/etc/my.cnf和/etc/mysql/conf.d/override.cnf),后者覆盖了前者——用mysqld --verbose --help | grep "Default options"看实际加载顺序 - 目录路径是符号链接,MySQL 5.7+ 会拒绝使用,必须是真实绝对路径(
/data/mysql/tmp可以,/data/mysql/tmp -> /mnt/ssd/tmp不行) - 目录存在但权限不对:MySQL 进程用户(如
mysql)必须对整个路径有读、写、执行权限,包括父目录;chmod 750是底线,700更稳妥 - SELinux 启用时未打标(RHEL/CentOS):
chcon -t mysqld_tmp_t /data/mysql/tmp缺失会导致启动失败或静默 fallback 到/tmp - 配置写在了
[client]或[mysql]段,而不是[mysqld]段
tmpdir 路径选在哪里才算“靠谱”
不是“越快越好”,而是“稳中求快”。把 tmpdir 指向 /dev/shm 确实快,但代价是 OOM killer 可能直接干掉 MySQL 进程——这不是性能优化,是赌命。
- 首选:单独挂载的 SSD/NVMe 分区,比如
/mnt/ssd/mysql-tmp,与datadir物理隔离,避免 IO 竞争 - 禁用 NFS 挂载点:MySQL 明确不支持,会报错或行为异常
- 禁用 root 分区(如
/tmp所在分区):日志、系统更新、其他服务都可能把它撑爆 - 禁用
/tmp或/var/tmp:公共目录易被清理、权限宽松、常挂载为noexec/nosuid - Linux 下不推荐多路径轮询(如
tmpdir = /disk1/tmp,/disk2/tmp):只认第一个,且无法负载均衡
tmpdir 和 innodb_temp_data_file_path 的区别与协同
这两个参数管的是完全不同的临时文件,混用或只调一个等于只修半边车:
-
tmpdir:控制 SQL 层面产生的临时文件位置,比如ORDER BY排序中间结果、GROUP BY聚合暂存、子查询临时表、ALTER TABLE重建过程中的临时文件 -
innodb_temp_data_file_path:只影响 InnoDB 内部使用的临时表空间(ibtmp1),用于内部排序、索引创建等,和用户 SQL 无直接关系 - 两者都应指向高速独立存储,但路径不能共用同一挂载点——否则仍是 IO 竞争
- 例如可配成:
tmpdir = /mnt/ssd/mysql-tmp,同时innodb_temp_data_file_path = /mnt/ssd/mysql-ibtmp/ibtmp1:512M:autoextend:max:10G
验证是否真起作用,别只看 SHOW VARIABLES
光确认 SHOW VARIABLES LIKE 'tmpdir' 输出正确远远不够。真正要盯的是运行时行为:
- 用
sudo -u mysql touch /mnt/ssd/mysql-tmp/test测试写入权限是否真实可用 - 执行一个明确触发磁盘临时表的查询(比如
SELECT * FROM huge_table ORDER BY non_indexed_col LIMIT 1),然后ls -lt /mnt/ssd/mysql-tmp/看是否有新#sql_*文件生成 - 监控状态变量:
SHOW GLOBAL STATUS LIKE 'Created_tmp%',重点关注Created_tmp_disk_tables是否下降;若比例仍长期 >15%,说明问题不在路径,而在tmp_table_size或 SQL 本身 - 注意:
tmpdir不影响内存临时表(由tmp_table_size和max_heap_table_size控制),它只决定“不得不落盘时往哪写”
最常被跳过的一步是:没确认目标路径的磁盘剩余空间是否足够。一次大排序可能瞬时写入数 GB 临时文件,而 df -h 显示还有 20% 空间,不代表有连续大块——尤其在 ext4 默认启用 5% 保留空间的情况下,实际可用可能远低于预期。











