ALTER大表磁盘不足的根本原因是MySQL默认需至少2倍原表空间创建临时表;tmpdir仅对COPY算法生效,且须满足权限、文件系统等条件,而INPLACE、pt-osc、ibdata1场景下无效。

ALTER大表时磁盘空间不足的根本原因
MySQL执行ALTER TABLE(尤其加索引、改列类型、重写行格式)时,默认会创建临时表,数据全量拷贝+排序+重建索引,这个过程需要**至少 2 倍原表大小的空闲空间**(原表 + 新表 + 日志/排序缓冲)。若/tmp或datadir所在分区已满,操作直接失败并报错:ERROR 1034 (HY000): Sort aborted: Server has gone away 或更常见的 ERROR 1038 (HY000): Out of sort memory(实际是磁盘而非内存)。
如何让ALTER走指定磁盘路径(TmpDir)
关键不是改tmpdir变量就能生效——InnoDB在ALTER TABLE ... ALGORITHM=INPLACE不适用时(如加全文索引、改CHAR长度),强制走COPY算法,此时它**只认tmpdir,且要求该路径有足够空间 + MySQL进程有读写权限 + 文件系统支持大文件**。
- 确认当前
tmpdir:SELECT @@tmpdir;
- 修改配置(需重启或动态设置):
SET GLOBAL tmpdir = '/data/mysql_tmp';
(注意:仅对新连接生效;若要持久化,写入my.cnf的[mysqld]段并重启) - 路径必须由MySQL用户(如
mysql)拥有:chown mysql:mysql /data/mysql_tmp && chmod 750 /data/mysql_tmp
- 验证是否生效:执行
SHOW VARIABLES LIKE 'tmpdir';,再跑一个ALTER TABLE t1 ADD INDEX idx_x(x);观察/data/mysql_tmp下是否出现#sql-*.ibd或#sql-*.MYD临时文件
tmpdir不是万能解药:这些情况它根本不起作用
tmpdir只影响临时表和排序文件的存放位置,但以下场景它完全无效:
- InnoDB在线DDL(
ALGORITHM=INPLACE)本身不建临时表,不走tmpdir,但会锁表或阻塞DML,且仍需redo log和undo空间 —— 这部分空间在innodb_log_group_home_dir和datadir里,无法通过tmpdir转移 - 使用
pt-online-schema-change或gh-ost时,它们自己管理临时表路径(如--chunk-index或--database指定库),与MySQL的tmpdir无关 - 如果原表在
innodb_file_per_table=OFF模式下,所有表数据都挤在ibdata1里,ALTER即使成功,也无法释放旧空间 —— 此时tmpdir再大也救不了磁盘持续膨胀
比改tmpdir更可靠的三件事
临时换路径只是治标。真正压倒性的问题往往出在设计和运维层面:
- 提前清理:
OPTIMIZE TABLE前先DELETE无用历史数据,并ANALYZE TABLE更新统计信息,减小ALTER实际处理量 - 分批操作:对超大表,用
pt-online-schema-change --chunk-size=1000 --max-load="Threads_running=20"控制资源消耗,避免单次占满磁盘 - 检查
innodb_sort_buffer_size(默认1M):太小会导致频繁磁盘排序;太大又吃内存。对大表ALTER,可临时调到4–8M(需评估内存余量)
真正容易被忽略的是:tmpdir路径不能是NFS或某些网络文件系统,MySQL对它的原子写和fsync行为不兼容,可能导致ALTER中途崩溃且无法回滚。


















