概述

最近为了对 MySQL 数据库磁盘占用瘦身,对一张近100GB表的历史数据进行了 delete 删除,删除了约2/3的数据,删除后发现该表占用的空间并未减少。通过下面语句查看该表的磁盘占用情况:

SELECT
TABLE_NAME AS `表名`,
ROUND(DATA_LENGTH / 1024 / 1024 / 1024, 2) AS `数据大小(GB)`,
ROUND(INDEX_LENGTH / 1024 / 1024 / 1024, 2) AS `索引大小(GB)`,
ROUND(DATA_FREE / 1024 / 1024 / 1024, 2) AS `碎片空间(GB)`,
ROUND((DATA_LENGTH + INDEX_LENGTH + DATA_FREE) / 1024 / 1024 / 1024, 2) AS `预估总占用(GB)`
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = 'mp_limitation_global'
ORDER BY
(DATA_LENGTH + INDEX_LENGTH)
DESC;

发现总的空间并没有发生变化,只是表数据空间减小,而碎片空间大幅上升:

所以,为什么数据删除了,表占用的磁盘空间却没有释放?

这里先交代一下全文 MySQL 相关的论述的基础:MySQL 版本为5.7.36,存储引擎为 InnoDB,参数innodb_file_per_table=ON。


为什么删除数据表空间未释放?

为了解释这个问题,先探究一下 MySQL 数据删除的过程。

如上图,现在要删掉 R7 这个记录,InnoDB 引擎只会把 R7 这个记录标记为删除,以待后续复用,但磁盘文件的大小并不会缩小。由于 InnoDB 的数据是按页存储的,那么如果删掉了一个数据页上的所有记录,整个数据页就也是可以被复用的。

然而,数据页的复用跟记录的复用是不同的。

记录的复用,只限于符合范围条件的数据:比如上面的假设,R7 这条记录被删除后,如果插入一个 ID 是 008 的行,那么可以直接复用这个空间;但如果插入的是一个 ID 是 012 的行,就不可以复用这个位置了。

数据页的复用,是当整个页从 B+ 树里面删掉以后,可以复用任何位置:以上图为例,如果将数据页 page A 上的所有记录被删除以后,page A 就会被标记为可复用,但是磁盘上的文件不会变小。

所以,delete 命令其实只是把记录的位置或数据页标记为了「可复用」,但不会改变磁盘文件的大小,即只通过 delete 是不能释放表空间的。这些可以复用,而又没有归还给操作系统的空间,看起来就像是“干净的地板上散落的碎片”。

如果能把这些碎片清理干净,那么就达到释放表空间的目的。


如何释放碎片占用的空间?

查阅 MySQL 官方文档-Defragmenting a Table,发现可以使用如下语句整理碎片:

ALTER TABLE tbl_name ENGINE=INNODB;

当然也可以使用下面的的语句整理碎片:

ALTER TABLE tbl_name FORCE;

这两种操作都使用到了在线 DDL 来重建表。那在线 DDL 又是什么?

在线 DDL 重建表的流程是什么?

使用ALTER 语句重新表的在线 DDL 机制大致如下:

  1. ALTER语句在初始化启动的时候需要获取 MDL 写锁;

  2. MDL写锁在真正拷贝数据之前就退化成读锁,MDL 读锁不会阻塞增删改等 DML 操作,InnoDB把这些操作记入 ROW_LOG;

  3. 最后完成存量数据相关拷贝,MDL 升级为独占锁,重放 ROW_LOG以写入增量数据。

而整个 DDL 最耗时的过程就是拷贝目标表数据到中间表文件的过程,这个过程中又可以增删改数据,而相对于整个 DDL 过程来说,锁的时间非常短,所以对业务来说,就可以认为是没有中断且在线的,这就是称为在线 DDL 的缘由,官方称之为 Online DDL。

在 Online DDL 过程中哪些操作可以触发重建表,哪些操作是“原地”或称“就地”操作,官方给出了详细说明,这里罗列一些开发中常见的一些操作:





Online DDL 过程中会产生临时文件,而这些临时文件也需要占用磁盘空间,对应的磁盘空间要求,官方也出了明确描述

上面的 ALTER 语句在 MySQL 5.7下隐含的意思其实是:

ALTER TABLE tbl_name engine=innodb,ALGORITHM=INPLACE;

同时整个过程不需要经过服务层搬运数据,整个过程是在 InnoDB 内部完成的,是一个“原地”、“就地”操作,这就是称为“inplace”的来源。

跟 INPLACE 相对应的就是拷贝表:

ALTER TABLE tbl_name engine=innodb,ALGORITHM=COPY;

当使用 ALGORITHM=COPY 的时候,表示的是强制拷贝表,这是 MySQL5.6版本以前的重建表流程:

  1. MySQL服务层触发创建临时表,对源表加MDL锁,阻塞DML写而不阻塞DML读;

  2. MySQL服务层从目标表中逐行读取数据,写入到临时表;

  3. 数据拷贝完成后,禁止读写,删除目标表,把临时表重命名为目标表。

上面的流程大致如下图:

如何理解 INPLACE 和 COPY

想象一个堆着货物又杂乱无章的仓库,现在要进行整理,以充分利用仓库内的空间:

INPLACE 就是在仓库内部整理,货物不用搬出仓库,货物按照编号摆放到货架。在这个过程中,可能要从货架临时取出一些货物,把它们放到仓库内指定的某处,以腾出空间排放正确编号的货物,所以仓库要有足够的空间,来临时堆放那些从货架临时取出的货物;

COPY 就是把仓库里的货物从货架取出,然后全部搬到仓库外面指定的某个场地(这个场地的空间需要足够大,以容纳所有货物),然后再按照编号顺序一件一件的搬回仓库,放到货架。

操作注意事项

  • 由于通过 Online DDL 方式整理碎片的过程中会产生和原数据表空间大小几乎规模相当的临时文件,所以执行前一定要确认 MySQL 磁盘剩余可用空间是否足够;

  • Online DDL在ALTER表过程中,会通过过 ROW_LOG 临时文件记录当时的并发 DML 操作,这个临时文件的大小上限由参数innodb_online_alter_log_max_size决定(默认大小128MB),所以要在业务低峰期操作碎片整理,保证没有大量 DML 操作,或者调整innodb_online_alter_log_max_size大小;

  • 在碎片整理过程中,可以通过以下方式来监控整理过程:

-- 监控磁盘临时文件
SHOW STATUS LIKE 'Created_tmp_disk_tables';
SHOW STATUS LIKE 'Created_tmp_files'; -- 查看正在进行的 DDL 操作
SELECT * FROM information_schema.INNODB_TRX;

附录:

Online DDL 参考文档


欢迎关注同名公众号,内容同步发布,移动端体验更好,你的关注是我持续创作的动力:

MySQL的表空间释放的更多相关文章

  1. [记录]一则清理MySQL大表以释放磁盘空间的案例

    一则清理MySQL大表以释放磁盘空间的案例 一.基本情况: 1.dbtest库554G,先清理st_online_time_away_ds(37G)表的数据,保留半年的数据: 1)删除的数据:sele ...

  2. MySQL的表空间管理

    表空间: MySQL没有真正意义上的表空间管理. MySQL的Innodb包含两种表空间文件模式,默认的共享表空间和每个表分离的独立表空间. 一般来说,当数据量很小的时候建议使用共享表空间的管理方式. ...

  3. mysql通过表空间来恢复或者传递数据

    mysql的备份工具通常有 mysqldump ,mysqlpump(5.7后新特性)等备份工具,这里我们可以尝试使用表空间进行传递 方式是:拷贝数据文件+拷贝表空间   对应innodb引擎就是 i ...

  4. 谈谈什么是MySQL的表空间?

    今天我要跟你分享的话题是:"大家常说的表空间到底是什么?究竟什么又是数据表?" 这其实是一个概念性的知识点,当作拓展知识.涉及到的概念大家了解一下就好,涉及的参数,留个印象就好. ...

  5. 使用MySQL传输表空间迁移数据

    对于大表的迁移,如果使用mysqldump进行导出,然后重新导入到其它环境,速度是非常缓慢的.如果使用传输表空间,则可以解决这个问题. 测试使用传输表空间迁移表,基础环境如下:   源库 目标库 IP ...

  6. mysql共享表空间转独立表空间

    使用innodb_export_import.py脚本: https://github.com/thecpaneladmin/innodb-tools 安装MySQL-python模块: shell ...

  7. 浅析mysql 共享表空间与独享表空间以及他们之间的转化

        innodb这种引擎,与MYISAM引擎的区别很大.特别是它的数据存储格式等.对于innodb的数据结构,首先要解决两个概念性的问题: 共享表空间以及独占表空间.什么是共享表空间和独占表空间共 ...

  8. mysql 案例 ~ 表空间迁移数据与数据导入

    一  简介:mysql5.6+的表空间传输二 目的:复制数据到另一个表三 步骤   1 create table b like a ->创建一个空表   2 alter table b disc ...

  9. mysql之 表空间传输

    说明:MySQL(5.6.6及以上),innodb_file_per_table开启. 1.1. 操作步骤: 0. 目标服务器创建相同表结构1. 目的服务器: ALTER TABLE t DISCAR ...

  10. MySQL 独立表空间恢复案例

    创建表的时候就会得到元数据.可以通过定义的方式对表的元数据进行生成 这个地方要注意的是 独立表空间当中   ibd & frm分别存储的是什么数据? 表空间:文件系统,为了更好的扩容数据库的存 ...

随机推荐

  1. Java进阶 - [1-1] 六大设计原则

    不要因为某本书而去读,而是因为这本书让你读起来时常有共鸣而去读. 一.单一职责原则 [术语]:SRP,Single Reposibility Principle [定义]:一个类或者模块只负责完成一个 ...

  2. C# async/await使用举例

    1.async/await几点总结 a.被async标记的方法,返回值类型只能为void.Task.Task<T>. b.被async标记的方法,内部可以有await修饰符,表明内部逻辑某 ...

  3. Web前端入门第 12 问:HTML 常用属性一览

    HELLO,这里是大熊学习前端开发的入门笔记. 本系列笔记基于 windows 系统. HTML 常用属性大约 70 个,是否又头大了?脸上笑嘻嘻,心里嘛...嘿嘿... 温馨提示:属性不用死记硬背, ...

  4. MySql 主从(备)部署 | 冷备份

    前言 MySQL 主从复制(Master-Slave Replication)是一种常见的数据库架构设计,用于提高数据可用性.实现读写分离以及支持备份策略.冷备份是指在数据库关闭状态下进行的数据备份方 ...

  5. [每日算法] leetcode第3题:无重复字符的最长子串

    leetcode第3题入口 题目描述 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: s = "abcabcbb" 输出: 3 解法1: ...

  6. Zotero 设置坚果云同步(使用 WebDAV 的方法)

    1.坚果云设置 登录坚果云:官网,注册账号 1.建立个人文件夹:zotero 2.在网页打开右上角的 账户信息,并选择 安全选项 在页面下方选择 添加应用 并输入与前面文件夹对应的名称 zotero ...

  7. 在 ThinkPHP 6 控制器中使用文件锁机制

    创建锁管理类 首先,创建一个锁管理类来处理文件锁: namespace app\common\service; use Exception; class LockManager { private $ ...

  8. 请运行命令来卸载Oracle主目录

    卸载Oracle数据库碰见的一个不一样的操作,留爪. 正常点的软件卸载直接点卸载即可, Oracle 卸载非要来点不一样警告, 如图: 注意:不要被图里的斜杠符号忽略了,准确的应该是: # 注意斜杠 ...

  9. $.ajax jsonp parsererror

    场景重现 通过$.ajax()发起的跨越请求代码如下: $.ajax({ dataType: "JSONP", type: "GET", url: " ...

  10. TdxpageControl融合窗口和free

    for I := cxpgcntrl1.PageCount - 1 downto 0do begin if cxpgcntrl1.Pages[i].Caption <> '首页' then ...