MySQL 实战 45 讲
林晓斌
网名丁奇,前腾讯云数据库负责人
224873 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
实践篇 (37讲)
特别放送 (1讲)
结课测试 (1讲)
MySQL 实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

13 | 为什么表数据删掉一半,表文件大小不变?

MDL锁
流程
ON
OFF
重建表的注意事项
Online DDL 的适用场景
重建表的两种实现方式
收缩表空间的方法
analyze table
optimize table
区别与联系
inplace
Online DDL
alter table 命令
空洞的产生
数据页的复用
记录的复用
B+树索引示意图
推荐做法
innodb_file_per_table 参数
动态平衡的损失
内存淘汰脏页和 redo log 的关系
磁盘压力和性能下跌
redo log 设置过小的影响
总结
其他重建方法
重建表
数据删除流程
表数据存储方式
上期问题回顾
数据库表空间回收

该思维导图由 AI 生成,仅供参考

经常会有同学来问我,我的数据库占用空间太大,我把一个最大的表删掉了一半的数据,怎么表文件的大小还是没变?
那么今天,我就和你聊聊数据库表的空间回收,看看如何解决这个问题。
这里,我们还是针对 MySQL 中应用最广泛的 InnoDB 引擎展开讨论。一个 InnoDB 表包含两部分,即:表结构定义和数据。在 MySQL 8.0 版本以前,表结构是存在以.frm 为后缀的文件里。而 MySQL 8.0 版本,则已经允许把表结构定义放在系统数据表中了。因为表结构定义占用的空间很小,所以我们今天主要讨论的是表数据。
接下来,我会先和你说明为什么简单地删除表数据达不到表空间回收的效果,然后再和你介绍正确回收空间的方法。

参数 innodb_file_per_table

表数据既可以存在共享表空间里,也可以是单独的文件。这个行为是由参数 innodb_file_per_table 控制的:
这个参数设置为 OFF 表示的是,表的数据放在系统共享表空间,也就是跟数据字典放在一起;
这个参数设置为 ON 表示的是,每个 InnoDB 表数据存储在一个以 .ibd 为后缀的文件中。
从 MySQL 5.6.6 版本开始,它的默认值就是 ON 了。
我建议你不论使用 MySQL 的哪个版本,都将这个值设置为 ON。因为,一个表单独存储为一个文件更容易管理,而且在你不需要这个表的时候,通过 drop table 命令,系统就会直接删除这个文件。而如果是放在共享表空间中,即使表删掉了,空间也是不会回收的。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了MySQL中InnoDB引擎下的数据库表空间回收问题,特别是在删除数据后表文件大小未发生变化的情况。首先介绍了InnoDB表的组成结构和参数innodb_file_per_table的作用,建议将该参数设置为ON以便更好地管理表空间。随后详细说明了数据删除流程,包括记录和数据页的复用,以及删除和插入数据可能导致的空洞问题。最后,介绍了通过重建表来收缩表空间的方法,包括使用alter table命令和优化流程。此外,还提到了GitHub开源的gh-ost工具,用于更安全地操作大表的重建。总的来说,本文对InnoDB表空间回收的原理和方法进行了深入浅出的解释,对于处理数据库表空间问题的读者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《MySQL 实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(206)

  • 最新
  • 精选
  • 发条橙子 。
    置顶
    老师 , 我的确实是 5.7 版本。我今天看了些关于 online ddl的文章 ,再结合表锁那章评论的内容,有几个点还想确认一下 ,希望老师能解答一下 。 1. 是不是 5.6 之后 所有的 alter 操作(增删字段、增删索引等)都是支持 online ddl 2. 如果 alter 都是 online ddl 那么是不是如果 alter操作 获取到mdl写锁 时, 后面的 查询需要mdl读锁会暂时阻塞, 但是mdl会马上降为读锁 ,后面的操作会继续进行不会堵塞 。等再升到写锁 ,后面操作又会暂时阻塞。 3. 当 alter 降到mdl 读锁时 , 这时候可以新增数据么 , mdl表级读锁 不会影响到 insert 或者 update的行锁么 4. 如果将 alter 操作显式的放到事务里 ,事务不提交 , 另一个事务查询的时候会查询到alter 操作后的表结构 , 比如新增了一个字段。这个是什么原因 ,是否打破了 mvcc 的定义呢

    作者回复: 1. 不是哦,我文章里说的加全文索引就不online 2. 对,这两个暂时,都是时间很短的 3. 是,DML语句加的是MDL读锁,读读不冲突 4. 好问题 , 不过alter table 语句会默认提交前面的事务,然后自己独立执行😄

    2018-12-13
    9
    86
  • 陈飞
    置顶
    老师,请问下分布式ID(雪花算法生成的ID)生成的索引会比自增长的ID性能低吗? 雪花算法生成的ID是越来越大的,但不是逐渐递增,长度用的的bitint,麻烦解答下,非常感谢。

    作者回复: 好问题。 性能一样的,没有一定要“连续”,只要是递增

    2018-12-13
    6
    194
  • 置顶
    麻烦咨询个问题,“在图 3 中,我们把表 A 中的数据导出来的存放位置叫作 tmp_table。这是一个临时表,是在 server 层创建的。” 在server层创建的表也是将A表数据copy到了临时表,为什么在空间不够用时就没有问题,而inplace在InnoDB执行则会再占用一份存储?

    作者回复: 额, Copy的时候肯定更要的… 这里特别指出来,是因为大多数人很容易理解copy需要临时空间,但是误以为inplace不需要 Anyway,好问题 😄

    2018-12-13
    8
    34
  • undifined
    置顶
    老师,有几个问题: 1.Truncate 会释放表空间吗 2.重建表的时候如果没有数据更新,有没有可能产生页分裂和空洞 3.页分裂是发生在索引还是数据上 4.应用 row log 的过程会不会再次产生页分裂和空洞 5.不影响增删改,就是 Online;相对 Server层没有新建临时表,就是 inplace,这里怎么判断是不是相对 Server 层没有新建临时表 辛苦老师解答一下,谢谢老师

    作者回复: 1. Truncate 可以理解为drop+create 2. Online 可以认为没有 3. 数据也是索引哦 4. 可能会 5. 好问题,我放到明天答疑部分

    2018-12-12
    14
    119
  • 飞翔
    我想到的其中一种可能: 本来就很紧凑,没能整出多少剩余空间。 重新收缩的过程中,页会按90%满的比例来重新整理页数据(10%留给UPDATE使用), 未整理之前页已经占用90%以上,收缩之后,文件就反而变大了。

    作者回复: 一个漂亮的答案

    2018-12-12
    19
    305
  • 帆帆帆帆帆帆帆帆
    @undifined怎么判断是不是相对 Server 层没有新建临时表。一个最直观的判断方法是看命令执行后影响的行数,没有新建临时表的话新建的行数是0。

    作者回复: 👍🏿,下一篇答疑直接贴你答案😄

    2018-12-12
    8
    94
  • Mr.Panda
    很喜欢作者的MySQL,绝对干货哈哈。 这里针对空洞提下问题: 1.删除有空洞,是因为标记了已删除可复用的节点位置,不会释放。 2.随机插入有空洞,是因为数据页分裂造成。 3.但更新有空洞,有点费解,我个人理解是更新是结合删除和插入的一个合并操作。删除后产生的空洞,在插入时不是应该就马上被复用了吗,毕竟主键是一致的。所以为什么更新会产生空洞呢??

    作者回复: 3. 可以这么想下,如果1,2,3,4,5 然后update把2 改成6, 如果原地修改,这个索引就不是“有序”的了

    2019-01-29
    21
    93
  • null
    临时表插入数据时,不允许表 A 有增删改操作,否则会造成数据丢失。所以表数据 copy 的方式不是 online 的。 而 inplace 的方式,在构建临时文件时,允许表 A 有增删改操作,期间新的增删改操作会记录到另外的日志文件,表 A 数据页的所有数据复制完成后,再应用日志文件(自己理解:应用日志文件时,不允许对表 A 增删改操作,即非 online 的)。整体操作是 online 的。 切换表名或临时文件时,需要获取 MDL 写锁。 inplace 表示在 innodb 引擎完成所有操作,对 server 层是透明的。inplace 操作不一定是 online 的,如 MySQL 8.0 的添加全文索引和空间索引。而 online 的一定是 inplace 的。

    作者回复: 👍

    2019-02-10
    4
    59
  • wang chen wen
    optimize table t 等于 recreate+analyze 老师请教个问题recreate出来应该是几乎全新的,analyze的必要性?

    作者回复: 好问题,这个得是比较极端的情况下才有必要,所以我比较喜欢直接用alter

    2018-12-12
    3
    32
  • 某、人
    通过第10期的课后思考题学习到如果delete的数据还会被用于MVCC,那么该数据页(二级索引和聚簇索引)上的记录不会被物理删除,是被标记删除。只有当该事务不会用于mvcc了,才可以被purge线程把之前标记删除的数据真正删除掉.但是即便数据物理删除了,磁盘空间也不会返回给操作系统.可以通过show table status like 't';观察data_free来预估该表的碎片。如果过大,可以用alter table t engine=innodb来清除 我有几个问题请教下老师: 1.inplace相对于其他在线改表软件,多了MDL X锁.既然都是通过临时表/文件来做,为什么一开始要上MDL X锁? 2.gh-ost使用binlog来做同步,假设从position 1开始,先lock S前面1000条数据做cp,这时有事务对后面1000条数据做了修改或者插入。等cp后面这个1000条时,会把修改好的数据cp到临时表.最后又应用binlog,那么这相当于做了两次操作,请问这部分数据是怎么处理的? 3.online会把过程中对表的操作记录在一个(row log)中,那么中途这些DML事务,是怎么判定的commit?我做测试,中途这些事务都是成功的。但是有在做online DDL快完了,commit那个阶段,DDL报唯一键冲突,这又是什么原因造成的啊?我没有模拟出来这个例子

    作者回复: 1. 确保没有启发请求在用这个表 2. Binlog设置为row格式,幂等的 3. 这个我觉得其实是bug,就没提。你在DDL期间,往原表插入一个已经存在相同主键的一行试试

    2018-12-13
    7
    29
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部