MySQL 磁盘空间紧急处置指南 — 哪些文件能删,哪些绝不能动
来源:运维派 | 发布日期:2026-07-12 原文:https://mp.weixin.qq.com/s/sLJPAxrK9ZngyvxeIfuNBw
MySQL 磁盘告警最危险的处理方式,是进入数据目录按大小执行 rm。InnoDB 数据、redo、undo、doublewrite、二进制日志和复制元数据之间存在恢复关系;错误删除可能立刻中断复制,也可能等重启时才暴露数据损坏。本文适用于 MySQL 8.0 + InnoDB。
一、先确认哪个文件系统满了
MySQL 文件可能分散在数据目录、binlog 目录、临时目录、错误日志目录和备份目录:
df -hT
df -i
mysql -NBe "SHOW VARIABLES WHERE Variable_name IN ('datadir','log_bin_basename','log_error','tmpdir','innodb_tmpdir');"
变量返回的路径才是事实依据——不要假设 binlog 必在 /var/lib/mysql。若 df 已满而 du 不大,检查已删除但仍被 mysqld 打开的文件:
sudo lsof +L1 | rg 'mysqld|mysql'
空间只有在持有 fd 的进程关闭文件后才释放,不要为了释放空间直接 kill mysqld。
二、信息收集:先采集,不删除
sudo du -xhd1 /var/lib/mysql | sort -h
sudo find /var/lib/mysql -xdev -maxdepth 1 -type f -printf '%s %p\n' | sort -n
从 MySQL 内部确认状态:
SELECT @@read_only, @@super_read_only, @@log_bin, @@binlog_format;
SHOW MASTER STATUS;
SHOW BINARY LOGS;
SHOW REPLICA STATUS\G
大表从字典统计确认,不能只凭 .ibd 文件名猜测:
SELECT table_schema, table_name, engine, table_rows,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb,
ROUND(data_free / 1024 / 1024, 2) AS data_free_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'sys', 'performance_schema', 'information_schema')
ORDER BY (data_length + index_length) DESC LIMIT 30;
三、核心:哪些能清,哪些绝不能动
| 对象 | 能直接 rm? |
正确处理方式 |
|---|---|---|
binlog.* |
❌ 不能 | PURGE BINARY LOGS,先确认复制与 PITR |
ibdata1、ibdata* |
❌ 绝不能 | 完整迁移/重建流程,InnoDB 系统表空间损坏 |
ib_logfile*、redo 目录 |
❌ 绝不能 | 当前版本支持的受控流程 |
#ib_*.dblwr (doublewrite) |
❌ 绝不能 | 由 InnoDB 自动管理 |
*.ibd |
❌ 不能 | DROP TABLE 或受控迁移 |
undo_* |
❌ 绝不能 | InnoDB 自动或受支持流程 |
relay-log.* |
❌ 不能 | 复制管理命令处理 |
| 错误/慢/general 日志 | ⚠️ 不应直接删 | 轮转 → reopen → 验证 |
ibtmp1 |
❌ 不要手工删 | 定位临时表压力 |
| 备份文件 | ⚠️ 可在确认策略后删除 | 保留期、校验、异地副本 |
"不能直接删"不是"先删后修"的意思。应优先让 MySQL、备份系统或日志轮转机制更新自身元数据。
四、Binlog:最常见空间来源
先确认 binlog 目录、文件列表和自动保留设置:
SHOW BINARY LOGS;
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW VARIABLES LIKE 'log_bin_basename';
安全清理流程——满足"所有副本不再需要、PITR 归档已确认、审批已通过"后:
PURGE BINARY LOGS TO 'binlog.000123'; -- 删除严格早于该文件的日志
-- 或按时间
PURGE BINARY LOGS BEFORE '2026-07-01 00:00:00';
- 文件名必须来自
SHOW BINARY LOGS,不能手写 - 时间范围受时区影响,先确认
@@global.time_zone - 执行前检查每个副本状态 + 备份归档完整性
- 绝不能用
rm binlog.*代替——手工删除让 index 文件与实际不一致
五、错误日志与慢日志:先轮转,别直接清空
SHOW VARIABLES WHERE Variable_name IN ('log_error','slow_query_log','slow_query_log_file','general_log','general_log_file','log_output');
若 log_output=FILE,安全做法是沿用已有 logrotate 机制:
sudo rg -n 'mysql|mysqld' /etc/logrotate.conf /etc/logrotate.d 2>/dev/null
sudo lsof -p "$(pgrep -o mysqld)" | rg '\.err|slow|general'
general_log 会带来高日志量和性能开销,经确认后可通过 SQL 关闭:SET GLOBAL general_log = 'OFF';
六、表空间:删了数据为什么文件未必变小
启用独立表空间时(innodb_file_per_table=ON),DROP TABLE 可释放 .ibd;共享表空间的行为不同。绝不能从 OS 删除 .ibd 文件。
删除数据前做只读核对和执行计划:
SELECT COUNT(*) FROM appdb.event_log WHERE created_at < '2025-01-01 00:00:00';
EXPLAIN SELECT COUNT(*) FROM appdb.event_log WHERE created_at < '2025-01-01 00:00:00';
大批量 DELETE 原则:小批、可停止、每批提交,批间检查复制延迟与锁等待。
OPTIMIZE TABLE不是满盘时的急救命令——它需要额外临时空间,磁盘接近满时可能失败。
七、临时表空间、Redo、Undo
ibtmp1 运行中绝不能删除。异常增长时应排查大排序、无索引 join、长事务:
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id, trx_query
FROM information_schema.innodb_trx ORDER BY trx_started;
查询为空只说明当前没有活动事务。不要为了"清 undo"随意杀连接——终止事务会回滚,反而持续占用 I/O。
八、紧急处置顺序
空间极低时的操作顺序:
- 确认满盘挂载点和最大文件类型
- 确认最近备份、binlog 归档与恢复链
- 在安全范围后 SQL purge binlog
- 按既有体系轮转日志
- 规划业务数据归档与表重建
- 必要时按流程扩容卷或迁移非数据类文件
不可执行的操作:
rm -f /var/lib/mysql/*、删除ibdata1、ib_logfile*、undo、doublewrite、.ibd、relay log- 未核对副本和 PITR 就删 binlog
- 用
TRUNCATE代替经过确认的数据治理 - 为释放空间而强制停止 mysqld
每次操作后从系统与 MySQL 两侧验证:
df -hT
df -i
sudo lsof +L1 | rg 'mysqld|mysql'
SHOW BINARY LOGS;
SHOW REPLICA STATUS\G
SHOW GLOBAL STATUS LIKE 'Threads_connected';
关联页面
| 页面 | 关联点 |
|---|---|
| database-troubleshooting-checklist-mysql-redis | MySQL/Redis 速查清单,含故障6:磁盘写满(本篇的 companion 补充) |
| mysql-backup-selection-guide | 备份方案对比与选型,PITR 与 binlog 归档策略 |
| mysql-replication-guide | 主从复制与 GTID,binlog 清理对复制链的影响 |
| mysql-connection-troubleshooting-guide | MySQL 连接失败排查指南 — 7 类报错根因定位 + 修复验证流程 |
| mysql-performance-config | MySQL 性能调优,涉及 Buffer Pool 与表空间配置 |