概述

最近为了对 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. Processing多窗口程序范例(一)

    Processing学习到一定程度必定会关注源码,关注扩展功能,其中窗口创建是值得关注的技术点(实现多窗口).下面就以一个简单范例来展开讨论. 范例代码 主程序先上: package syf.demo ...

  2. 【论文随笔】推荐系统综述_推荐模型、推荐技术与应用领域(A Survey of Recommendation Systems_ Recommendation Models, Techniques, and Application Fields)

    前言 今天读的论文为一篇于2022年1月3日发表的论文,这篇文章是关于推荐系统的综述,主要研究了推荐系统在不同服务领域的应用趋势,包括推荐模型.技术和应用领域.通过分析2010年至2021年间发表的顶 ...

  3. vue+elementUI 表格操作按钮添加loading

    前言 表格操作栏,某个操作需要异步请求才能做跳转等 方案 整个列表每行都加一个loading字段,不够优雅 利用$set方法 改变当前行当前按钮loading,可行(代码如下) //按钮 row.lo ...

  4. Landsat遥感影像分幅条带介绍与矢量下载:WRS的Path与Row

      本文介绍Landsat系列卫星的分幅规则,并提供WRS的矢量文件下载.   WRS,即Worldwide Reference System,是Landsat系列卫星全球影像标记符号系统,用以区分全 ...

  5. DB读写分离情况下,如何解决缓存和数据库不一致性问题?

    前言 在读写分离的情况下,缓存和数据库数据不一致怎么解决? 请看这一篇如何更新缓存保证缓存和数据库双写一致性? 如何解决DB数据库的数据不一致问题? 请看这一篇怎么解决DB读写分离,导致数据不一致问题 ...

  6. 【VMware VCF】解决 VCF 环境中组件用户密码过期问题。

    由于长时间没有启动 VCF 环境,现在在启动 SDDC Manager 组件后,UI 一直处于如下图所示的"初始化"状态.当时第一直觉就认为肯定是 VCF 环境组件的用户密码过期了 ...

  7. 查看Unity3D中默认的变量名与按键的映射

    博客地址:https://www.cnblogs.com/zylyehuo/ 选择 Edit/Project Settings/Input Manager 点击 Axes 即可查看对应变量名与按键的映 ...

  8. SpringBoot + 布隆过滤器:亿级数据下的高效防护盾与缓存穿透实战指南

    在当今高并发.海量数据的应用场景中,布隆过滤器凭借其极低的内存占用和极快的查询效率,成为解决缓存穿透.数据预判等难题的利器.本文深度解析布隆过滤器的核心原理与实战应用,手把手教你如何将这一数据守门员融 ...

  9. PHP配置并使用mosquitto

    要在PHP中配置和使用Mosquitto,你需要进行以下步骤: 安装Mosquitto PHP扩展: sudo apt-get install php-mosquitto 在PHP配置文件中启用Mos ...

  10. php代码审计实战-开源项目Materialized CMS漏洞检测

    一.下载Materialized CMS 链接地址:https://sourceforge.net/projects/materialized-cms/files/latest/download 二. ...