MySQL 磁盘空间不足,哪些文件能删,哪些千万别动?17认证网

正规官方授权
更专业・更权威

MySQL 磁盘空间不足,哪些文件能删,哪些千万别动?

MySQL 磁盘空间不足,哪些文件能删,哪些千万别动?

MySQL 磁盘告警最危险的处理方式,是进入数据目录按大小执行 rm。InnoDB 数据、redo、undo、doublewrite、二进制日志和复制元数据之间存在恢复关系;有些文件应由 SQL 清理,有些只能通过受支持的停库或迁移流程处理,有些运行时绝不能碰。错误删除可能立刻中断复制,也可能等重启时才暴露数据损坏。

本文以 MySQL 8.0 和常见 InnoDB 表为重点。MySQL 5.7、MariaDB、云数据库的变量、复制语法和底层文件行为可能不同,先确认实际产品和版本:

   bash
mysql --version
mysql -NBe 'SELECT VERSION(), @@version_comment;'

示例输出:

   text
8.0.36	MySQL Community Server - GPL

下文中的库名、表名、日期、路径和 Pod 名均为示例,执行前必须替换为真实对象。mysql 命令假定认证已通过受控方式配置;不要将明文密码放入 shell 历史、脚本或工单。

一、现象:先确认到底哪个文件系统满了

MySQL 文件可能分散在数据目录、binlog 目录、临时目录、错误日志目录和备份目录。先看容量与 inode,不要只盯根分区:

   bash
df -hT
df -i
mysql -NBe "SHOW VARIABLES WHERE Variable_name IN ('datadir','log_bin_basename','log_error','tmpdir','innodb_tmpdir');"

示例输出:

   text
Variable_name	Value
datadir	/var/lib/mysql/
log_bin_basename	/var/lib/mysql/binlog
tmpdir	/tmp

变量返回的路径才是当前实例的事实依据。不要假设 binlog 必在 /var/lib/mysql,也不要假设错误日志必在数据目录。若 df 已满而 du 不大,检查“已删除但仍被 mysqld 打开”的文件:

   bash
sudo lsof +L1 | rg 'mysqld|mysql'

空间只有在持有 fd 的进程关闭文件后才释放。不要为了释放空间直接 kill mysqld;应先确认是哪个日志、它的轮转和重新打开方式。容器场景还要从声明式配置确认卷位置;Kubernetes 查询必须明确 namespace:

   bash
kubectl -n <namespace> get pod <mysql-pod-name> -o yaml
kubectl -n <namespace> get pvc

替换实际 namespace 与 Pod 名。不要在 Pod 或节点的卷内删除未知文件;先确认控制器、持久卷、备份和恢复责任边界。

二、信息收集:建立文件、表空间和拓扑关系

先采集,不删除。若 datadir 为其他路径,必须替换:

   bash
sudo du -xhd1 /var/lib/mysql | sort -h
sudo find /var/lib/mysql -xdev -maxdepth 1 -type f -printf '%s %p\n' | sort -n
sudo ls -lah /var/lib/mysql

-x 防止跨文件系统统计。大目录上的 du 可能有 I/O,应在低峰或限制范围执行。再从 MySQL 内部确认状态:

   sql
SELECT @@read_only, @@super_read_only, @@log_bin, @@binlog_format;
SHOW MASTER STATUS;
SHOW BINARY LOGS;
SHOW REPLICA STATUS\G

SHOW REPLICA STATUS 是 MySQL 8.0 语法;较旧 MySQL 常见 SHOW SLAVE STATUS。只能按实际版本选择。清理 binlog 前,必须在每个副本确认复制线程、错误、Source_Log_File、读取位置和延迟;GTID、多源、级联复制与托管服务还需按自身机制核对。

大表要从字典和 SQL 统计确认,不能只凭 .ibd 文件名猜测:

   sql
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;

InnoDB 的 table_rows 与 data_free 可能是估算值,不能据此直接删除数据。表空间相关字段在版本和表空间类型间可能不同,查询 INFORMATION_SCHEMA.INNODB_TABLESPACES 报列错误时先执行 DESCRIBE INFORMATION_SCHEMA.INNODB_TABLESPACES;,不要照搬其他版本列名。

三、哪些能清,哪些千万别手工动

对象
能否直接 rm
正确处理方式
主要风险
binlog.*

mysql-bin.*
不能
PURGE BINARY LOGS

,先确认复制与 PITR
副本不能追赶、恢复链中断
ibdata1

ibdata*
绝不能
完整迁移/重建流程
InnoDB 系统表空间损坏
ib_logfile*

、redo 目录
绝不能
当前版本支持的受控流程
崩溃恢复或启动失败
#ib_*.dblwr

 等 doublewrite 文件
绝不能
由 InnoDB 管理
恢复保护被破坏
*.ibd
不能
SQL DROP TABLE 或受控迁移
字典与表空间不一致
undo_*
绝不能
InnoDB 自动或受支持流程
事务与回滚段损坏
relay-log.*
不能
复制管理命令处理
副本状态损坏
错误/慢/general 日志
不应直接删
轮转、reopen 或 SQL 配置
审计丢失、空间不释放
ibtmp1
不要手工删
定位临时表压力
运行实例损坏
已完成备份
可在确认策略后迁移/删除
保留期、校验、异地副本
失去恢复能力

“不能直接删”不是“先删后修”的意思。释放空间应优先让 MySQL、备份系统或日志轮转机制更新自身元数据。

四、binlog:最常见空间来源,也是最容易误删的文件

先确认 binlog 目录、文件列表和自动保留设置:

   sql
SHOW BINARY LOGS;
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW VARIABLES LIKE 'expire_logs_days';
SHOW VARIABLES LIKE 'log_bin_basename';

MySQL 8.0 常使用 binlog_expire_logs_seconds;旧版本可能使用 expire_logs_days。变量存在不代表保留期一定满足副本与点时间恢复要求。备份系统若依赖 binlog 做 PITR,必须确认相关日志已经成功归档,且归档可与全量备份组合恢复。

满足“所有副本不再需要、PITR 归档已确认、审批已通过”后,使用 SQL 清理:

   sql
PURGE BINARY LOGS TO 'binlog.000123';

该语句删除严格早于 binlog.000123 的日志,保留指定文件本身。文件名必须来自 SHOW BINARY LOGS,不能手写猜测。按时间清理也可使用:

   sql
PURGE BINARY LOGS BEFORE '2026-07-01 00:00:00';

时间边界受服务器时区影响,先检查 @@global.time_zone@@session.time_zone 与系统时间,并留出安全余量。

这是高风险操作。影响范围是本机 PITR 窗口与所有下游副本;执行前检查每个副本状态、备份归档完整性、待删文件清单和磁盘告警;备份方式是确认已验证的全量备份加 binlog 归档链,而不是随手复制几个文件;生产主库没有真正 dry-run,应通过 SHOW BINARY LOGS 列出安全范围、双人复核和变更审批实现“执行前演练”;验证是 SHOW BINARY LOGSdf -h、所有副本状态和备份监控。回滚不能用 SQL 恢复已 purge 的本地 binlog,只能依赖已验证归档或重建副本,因此前置确认不完整时不得执行。

绝不能用 rm binlog.* 代替。手工删除会让 index 文件和实际文件不一致,错误可能在后续复制、恢复或重启时爆发。误删后应停止继续操作,保留目录清单与错误日志,评估副本和恢复链;不要伪造空文件或手改 index 文件。

五、错误日志、慢日志与 general log:先轮转,别直接清空

先查询日志写到文件还是表,以及真实路径:

   sql
SHOW VARIABLES WHERE Variable_name IN ('log_error','slow_query_log','slow_query_log_file','general_log','general_log_file','log_output');

log_output 可能为 FILETABLE 或两者。如果是 TABLE,日志可能写在 mysql.slow_logmysql.general_log,文件截断不适用。文件日志的安全做法是沿用已部署的 logrotate 或服务管理流程:先归档旧日志,再让 mysqld 重新打开文件,最后确认新文件持续写入。不同发行版和部署方式的 reopen 方式不同,不要凭记忆向生产 mysqld 发信号。

检查现有规则和 mysqld 实际打开文件:

   bash
sudo rg -n 'mysql|mysqld' /etc/logrotate.conf /etc/logrotate.d 2>/dev/null
sudo lsof -p "$(pgrep -o mysqld)" | rg '\.err|slow|general'

轮转影响日志连续性和审计。执行前检查路径、属主、空间与既有规则;备份为按保留策略归档旧日志;灰度在从库或测试实例验证轮转脚本;验证新日志 inode、mysqld fd 和新日志内容;回滚为恢复原轮转配置,不能用重启数据库代替。

general_log 会带来高日志量和性能开销。经安全、审计和业务确认后可通过 SQL 关闭:

   sql
SET GLOBAL general_log = 'OFF';

这会影响全实例通用查询审计,且是否跨重启持久取决于配置文件;它不是无条件空间清理命令。执行前确认依赖,记录恢复方式,按审批决定是否重新启用。

六、表空间:删了数据为什么文件未必变小

先查看独立表空间开关:

   sql
SHOW VARIABLES LIKE 'innodb_file_per_table';

启用独立表空间时,删除整张 InnoDB 表通常可以由 MySQL 释放对应 .ibd;共享表空间或历史对象的行为不同。无论哪种,绝不能从操作系统删除 .ibd。业务过期数据治理应先做只读核对和执行计划:

   sql
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';

appdb.event_log 与时间都必须替换为经业务确认的对象。没有合适索引时,大批量 DELETE 会造成长事务、锁等待、复制延迟和 undo/redo 压力。正确原则是小批、可停止、每批提交,并在批间检查副本、锁等待、延迟与业务错误。以下为伪代码,不能直接执行:

   text
伪代码:
循环执行经 DBA 审核的、按索引命中的小批删除;
每批提交后检查复制延迟、锁等待、redo/undo 压力和应用错误;
达到停止阈值立即停止后续批次;
直到经业务确认的保留边界没有剩余数据。

删除数据属于高风险操作。影响范围包括业务可用性、复制和恢复窗口;执行前需要业务保留规则、可恢复备份、删除行数估算和执行计划;备份必须已验证可恢复;灰度是先对小时间段/小分区或从库演练;验证剩余数据、关键业务和复制;回滚依赖备份、归档或业务重放,普通 DELETE 没有通用一键回滚。

OPTIMIZE TABLE 不是满盘时的急救命令。对 InnoDB,它常通过重建表/索引实现,所需额外空间、锁行为与在线 DDL 能力依 MySQL 版本和表结构而变。磁盘接近满时执行可能因临时空间不足失败甚至加剧 I/O。若需回收表空间,应作为独立迁移变更:在同版本测试环境演练,明确额外空间、锁、复制、备份、灰度和回滚方案。

七、临时表空间、redo、undo:空间增长通常只是根因的结果

ibtmp1 常见于 InnoDB 临时表空间,但位置与行为依配置和版本变化。运行中的 MySQL 绝不能删除它。它异常增长时,应查大排序、无索引 join、临时表和长事务;正常重启后它通常可重建,但重启会中断业务且未必解决 SQL 根因。

只读查看活动 InnoDB 事务:

   sql
SELECT trx_id,
       trx_started,
       trx_state,
       trx_mysql_thread_id,
       trx_query
FROM information_schema.innodb_trx
ORDER BY trx_started;

查询为空只说明当前时刻没有活动 InnoDB 事务。不要为了“清 undo”随意杀连接;终止事务会回滚,反而可能持续占用 I/O。redo、undo、doublewrite 与系统表空间都是恢复链的一部分。任何 redo 容量或数据库参数调整,都必须按当前版本支持方式,在完整备份、测试演练和变更审批后实施。

八、紧急处置、验证与长期维护

空间极低时的顺序应是:确认满盘挂载点和大文件类型;确认最近备份、binlog 归档与恢复链;在确认安全范围后 SQL purge binlog;按既有体系轮转日志;规划业务数据归档与表重建;必要时按平台流程扩容卷或迁移非数据类文件。不要执行:

  • rm -f /var/lib/mysql/*
    、删除 ibdata1ib_logfile*、undo、doublewrite、.ibd 或 relay log。
  • 未核对副本和 PITR 就删 binlog。
  • 用 TRUNCATE 代替经过确认的数据治理;它是 DDL,语义与恢复方式不同。
  • 为释放已删除但仍打开的文件而强制停止 mysqld。

每次操作后从系统与 MySQL 两侧验证:

   bash
df -hT
df -i
sudo lsof +L1 | rg 'mysqld|mysql'
   sql
SHOW BINARY LOGS;
SHOW REPLICA STATUS\G
SHOW GLOBAL STATUS LIKE 'Threads_connected';

验收不仅是“磁盘空出来了”,还要确认实例读写、错误日志、所有副本、备份任务与业务关键路径正常。Prometheus 中 MySQL 和主机指标名称、标签以实际 exporter 暴露的指标为准。长期告警应覆盖容量、inode、增长速率、binlog 增长、长事务、临时表、复制延迟和备份恢复演练。磁盘告警可以紧急,但数据一致性与可恢复性不能靠删文件来赌。

转自:运维SRE前栈

版权申明:内容来源网络,版权归原创者所有,如有侵权请联系删除

想了解更多干货,可通过下方扫码关注

可扫码添加上智启元官方客服微信👇

未经允许不得转载:17认证网 » MySQL 磁盘空间不足,哪些文件能删,哪些千万别动?
分享到:0

评论已关闭。

400-663-6632
咨询老师
咨询老师
咨询老师