【数据库实战】RDS磁盘告警但数据不多?InnoDB碎片回收与无锁重建的工程解法

举报
yd_271832976 发表于 2026/10/28 00:19:41 2026/10/28
【摘要】 针对云数据库(RDS for MySQL)在经历大量 DELETE 或 UPDATE 操作后,数据总行数下降但云盘空间(.ibd 文件)毫无缩减,甚至触发磁盘 100% 告警的痛点,本文提供一套基于数据空洞排查与 OPTIMIZE TABLE 无锁重建的工程化解法,实现表空间的秒级极速回收。

许多开发者在收到 RDS 磁盘满告警时,第一时间写了批处理脚本去 DELETE 千万级别的历史日志数据。但诡异的是,删除跑完后,df -h 查看底层磁盘空间居然一 MB 都没有释放。

这是因为 MySQL InnoDB 引擎的底层 B+ 树特性。执行 DELETE 只是将数据页标记为“可复用(Deleted)”,并没有将物理空间真正还给操作系统,这些未被释放的空洞被称为“表空间碎片(Fragmentation)”。

标准的工程排障解法是:精准定位碎片率极高的“毒瘤表”,并利用在线 DDL 技术重新整理底层物理页。

1. 极速扫描全库碎片率

不要盲目排查,直接连入 RDS,利用 information_schema.tables 字典表,揪出那些 DATA_FREE(碎片空洞)占据绝对物理空间的大表:

SQL
-- 查询全库各表的物理大小与碎片闲置空间,按碎片量倒序排列
SELECT 
    table_schema AS '数据库',
    table_name AS '表名',
    ROUND(data_length / 1024 / 1024, 2) AS '实际数据大小(MB)',
    ROUND(data_free / 1024 / 1024, 2) AS '碎片空洞大小(MB)',
    ROUND((data_free / (data_length + data_free)) * 100, 2) AS '碎片率(%)'
FROM information_schema.tables 
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
  AND data_free > 0 
ORDER BY data_free DESC 
LIMIT 10;

2. 在线无锁重建表空间(Online DDL)

定位到碎片率极高(如超过 30% 且体积达数十 GB)的表后,绝不能在业务高峰期直接执行原生的 OPTIMIZE TABLE,因为老版本 MySQL 会对全表加读写锁。 对于 MySQL 5.6 及以上版本,必须使用基于 INPLACE 算法的伪装 ALTER 命令,在不阻塞线上并发读写的情况下,让 InnoDB 在底层默默重建一个排列紧密的新 .ibd 文件并替换旧文件:

SQL
-- 💡 核心:指定 ALGORITHM=INPLACE 和 LOCK=NONE
-- 强令 MySQL 在重建 B+ 树物理结构时不阻塞当前线上的 DML(增删改)操作
ALTER TABLE business_logs ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;

3. 定期维保自动化脚本

碎片整理会消耗大量 CPU 与 I/O 资源,千万不要让其在白天触发。应将其沉淀为 DBA 自动化运维脚本,结合 Cronjob 在凌晨 3 点业务低谷期执行。如果表体积达到百 GB 级别,建议直接使用开源工具 gh-ost 或 pt-online-schema-change 以确保绝对的平滑。

总结: 云端数据库存储成本高昂,决不能让无用的“物理碎片”白白消耗预算。通过底层字典表的精准监控与无锁 ALTER 技术的配合,开发者可以在对前端业务彻底无感的情况下,完成数据库底盘的大扫除,是延长 RDS 实例生命周期的必备技能。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。