13 | 为什么表数据删掉一半,表文件大小不变?
13 | 为什么表数据删掉一半,表文件大小不变?
讲述:林晓斌
时长14:37大小13.36M
参数 innodb_file_per_table
数据删除流程
重建表
Online 和 inplace
小结
上期问题时间
赞 123
提建议
精选留言(199)
- 陈飞置顶2018-12-13老师,请问下分布式ID(雪花算法生成的ID)生成的索引会比自增长的ID性能低吗? 雪花算法生成的ID是越来越大的,但不是逐渐递增,长度用的的bitint,麻烦解答下,非常感谢。
作者回复: 好问题。 性能一样的,没有一定要“连续”,只要是递增
共 6 条评论178 - undifined置顶2018-12-12老师,有几个问题: 1.Truncate 会释放表空间吗 2.重建表的时候如果没有数据更新,有没有可能产生页分裂和空洞 3.页分裂是发生在索引还是数据上 4.应用 row log 的过程会不会再次产生页分裂和空洞 5.不影响增删改,就是 Online;相对 Server层没有新建临时表,就是 inplace,这里怎么判断是不是相对 Server 层没有新建临时表 辛苦老师解答一下,谢谢老师展开
作者回复: 1. Truncate 可以理解为drop+create 2. Online 可以认为没有 3. 数据也是索引哦 4. 可能会 5. 好问题,我放到明天答疑部分
共 14 条评论112 - 发条橙子 。置顶2018-12-13老师 , 我的确实是 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 语句会默认提交前面的事务,然后自己独立执行😄
共 8 条评论81 - 郜置顶2018-12-13麻烦咨询个问题,“在图 3 中,我们把表 A 中的数据导出来的存放位置叫作 tmp_table。这是一个临时表,是在 server 层创建的。” 在server层创建的表也是将A表数据copy到了临时表,为什么在空间不够用时就没有问题,而inplace在InnoDB执行则会再占用一份存储?
作者回复: 额, Copy的时候肯定更要的… 这里特别指出来,是因为大多数人很容易理解copy需要临时空间,但是误以为inplace不需要 Anyway,好问题 😄
共 8 条评论32 - 飞翔2018-12-12我想到的其中一种可能: 本来就很紧凑,没能整出多少剩余空间。 重新收缩的过程中,页会按90%满的比例来重新整理页数据(10%留给UPDATE使用), 未整理之前页已经占用90%以上,收缩之后,文件就反而变大了。
作者回复: 一个漂亮的答案
共 18 条评论279 - 钱2019-07-011:为啥删除了表的一半数8据,表文文件大小没变化? 因为delete 命令其实只是把记录的位置,或者数据页标记为了“可复用”,但磁盘文件的大小是不会变的。也可以认为是一种逻辑删除,所以物理空间没有实际释放,只是标记为可复用,表文件的大小当然是不变的啦! 2:表的数据信息存在哪里? 表数据信息可能较小也可能巨大无比,她可以存储在共享表空间里,也可以单独存储在一个以.ibd为后缀的文件里,由参数innodb_file_per_table来控制,老师建议总是作为一个单独的文件来存储,这样非常容易管理,并且在不需要的时候,使用drop table命令也能直接把对应的文件删除,如果存储在共享空间之中即使表删除了空间也不会释放。 3:表的结构信息存在哪里? 首先,表结构定义占有的存储空间比较小,在MySQL8.0之前,表结构的定义信息存在以.frm为后缀的文件里,在MySQL8.0之后,则允许把表结构的定义信息存在系统数据表之中。 系统数据表,主要用于存储MySQL的系统数据,比如:数据字典、undo log(默认)等文件 4:如何才能删除表数据后,表文件大小就变小? 重建表,消除表因为进行大量的增删改操作而产生的空洞,使用如下命令: 1:alter table t engine=InnoDB 2:optimize table t( 等于 recreate+analyze)。 3:truntace table t (等于drop+create) 5:空洞是啥?咋产生的? 空洞就是那些被标记可复用但是还没被使用的存储空间。 使用delete命令删除数据会产生空洞,标记为可复用 插入新的数据可能引起页分裂,也可能产生空洞 修改操作,有时是一种先删后插的动作也可能产生空洞展开共 1 条评论107
- Mr.Panda2019-01-29很喜欢作者的MySQL,绝对干货哈哈。 这里针对空洞提下问题: 1.删除有空洞,是因为标记了已删除可复用的节点位置,不会释放。 2.随机插入有空洞,是因为数据页分裂造成。 3.但更新有空洞,有点费解,我个人理解是更新是结合删除和插入的一个合并操作。删除后产生的空洞,在插入时不是应该就马上被复用了吗,毕竟主键是一致的。所以为什么更新会产生空洞呢??展开
作者回复: 3. 可以这么想下,如果1,2,3,4,5 然后update把2 改成6, 如果原地修改,这个索引就不是“有序”的了
共 21 条评论89 - 帆帆帆帆帆帆帆帆2018-12-12@undifined怎么判断是不是相对 Server 层没有新建临时表。一个最直观的判断方法是看命令执行后影响的行数,没有新建临时表的话新建的行数是0。
作者回复: 👍🏿,下一篇答疑直接贴你答案😄
共 7 条评论87 - null2019-02-10临时表插入数据时,不允许表 A 有增删改操作,否则会造成数据丢失。所以表数据 copy 的方式不是 online 的。 而 inplace 的方式,在构建临时文件时,允许表 A 有增删改操作,期间新的增删改操作会记录到另外的日志文件,表 A 数据页的所有数据复制完成后,再应用日志文件(自己理解:应用日志文件时,不允许对表 A 增删改操作,即非 online 的)。整体操作是 online 的。 切换表名或临时文件时,需要获取 MDL 写锁。 inplace 表示在 innodb 引擎完成所有操作,对 server 层是透明的。inplace 操作不一定是 online 的,如 MySQL 8.0 的添加全文索引和空间索引。而 online 的一定是 inplace 的。展开
作者回复: 👍
共 3 条评论55 - wang chen wen2018-12-12optimize table t 等于 recreate+analyze 老师请教个问题recreate出来应该是几乎全新的,analyze的必要性?
作者回复: 好问题,这个得是比较极端的情况下才有必要,所以我比较喜欢直接用alter
共 3 条评论31 - 某、人2018-12-13通过第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期间,往原表插入一个已经存在相同主键的一行试试
共 7 条评论26 - 壹口尘埃2018-12-19网上找到一个Inplace和Online的区别,写的挺好的,贴出来方便大家理解: MySQL各版本,对于add Index的处理方式是不同的,主要有三种: (1)Copy Table方式 这是InnoDB最早支持的创建索引的方式。顾名思义,创建索引是通过临时表拷贝的方式实现的。 新建一个带有新索引的临时表,将原表数据全部拷贝到临时表,然后Rename,完成创建索引的操作。 这个方式创建索引,创建过程中,原表是可读的。但是会消耗一倍的存储空间。 (2)Inplace方式 这是原生MySQL 5.5,以及innodb_plugin中提供的创建索引的方式。所谓Inplace,也就是索引创建在原表上直接进行,不会拷贝临时表。相对于Copy Table方式,这是一个进步。 Inplace方式创建索引,创建过程中,原表同样可读的,但是不可写。 (3)Online方式 这是MySQL 5.6.7中提供的创建索引的方式。无论是Copy Table方式,还是Inplace方式,创建索引的过程中,原表只能允许读取,不可写。对应用有较大的限制,因此MySQL最新版本中,InnoDB支持了所谓的Online方式创建索引。 InnoDB的Online Add Index,首先是Inplace方式创建索引,无需使用临时表。在遍历聚簇索引,收集记录并插入到新索引的过程中,原表记录可修改。而修改的记录保存在Row Log中。当聚簇索引遍历完毕,并全部插入到新索引之后,重放Row Log中的记录修改,使得新索引与聚簇索引记录达到一致状态。 与Copy Table方式相比,Online Add Index采用的是Inplace方式,无需Copy Table,减少了空间开销;与此同时,Online Add Index只有在重放Row Log最后一个Block时锁表,减少了锁表的时间。 与Inplace方式相比,Online Add Index吸收了Inplace方式的优势,却减少了锁表的时间。展开共 6 条评论25
- 库淘淘2018-12-13alter table A engine=InnoDB 中由写锁降为读锁。有个疑问 为何不直接就加个MDL读锁 ,这样DDL 也执行不了,应用redo 替换文件后释放读锁即可
作者回复: 如果有别的线程正在读这个表的数据,得等下
共 8 条评论21 - 阿杜2019-03-01我以前负责的一个系统就出现过这种情况,突然有个表的sql执行很慢,后来觉得是此表增删的数据很多,碎片很多,就执行了optimize table,立马就好了。看来就是老师文中说的,删除和增加都是空洞造成。
作者回复: 👍,找到正主了😆
共 3 条评论20 - Dylan2019-01-20看了这么多期的文章,感觉这个专栏真的是让我有爱有恨,喜欢的是让我能理解这些SQL语句背后的原理,恨的刚好也是这些原理理解起来很是费劲。 有一个问题想请教老师,关于MySQL的这些参数,对于之前没接触过的人来说,很多是不知道的,那我用的时候怎么知道说要设置哪个参赛比较适合呢
作者回复: 有爱有恨 😅 加油哈 这种我觉得可以这样,上网找一个“最佳实践”的建议,但是不要照搬,而是一个个去理解每个参数的意思,以及判断是否适合自己的业务 这样几次我觉得应该会慢慢有感觉起来
12 - WL2018-12-16把该讲内容总结为几个问题, 大家复习的时候可以先尝试回答这些问题检查自己的掌握程度: 1. innodb_file_per_table参数是什么意思, 一般如何设置更合理? 2. 删除数据和插入数据为什么会造成出现空间空洞的情况? 原因各是什么? 3. online DDL在重建表流程上比非online DDL的方式做了哪些流程上的优化? 4. Online和replace两个概念各是什么, 他们之间有什么样的区别?展开12
- 每天晒白牙2018-12-14针对@undifined的问题3:页分裂发生在索引上还是数据上?老师给的回答是 数据也是索引,老师是不是想表达 索引也是数据呢?
作者回复: 不是… 我的意思是,数据是放在主键索引的叶子节点的 “索引也是数据”这个是哲学问题,一切皆数据😄
共 3 条评论11 - 尘封2018-12-12老师,请教一个问题,和本文无关,既然mysql支持了打包数据排序模式,能够更紧凑的分配内存进行排序,那定义表结构的时候,varchar(10)存储hello和varchar(100)存储hello的优势在哪里呢?谢谢
作者回复: 你这个问题放在第16篇问就刚刚好了。 以前不支持紧凑排序的时候有,现在没啥了差别了,小于256都差不多
共 2 条评论11 - 是我的海2019-05-31二刷中++ 以下是老师回复一个同学的问题: +++++++++++++++++++++++ Mr.Panda 很喜欢作者的MySQL,绝对干货哈哈。 这里针对空洞提下问题: 1.删除有空洞,是因为标记了已删除可复用的节点位置,不会释放。 2.随机插入有空洞,是因为数据页分裂造成。 3.但更新有空洞,有点费解,我个人理解是更新是结合删除和插入的一个合并操作。删除后产生的空洞,在插入时不是应该就马上被复用了吗,毕竟主键是一致的。所以为什么更新会产生空洞呢?? 5 2019-01-29 作者回复: 3. 可以这么想下,如果1,2,3,4,5 然后update把2 改成6, 如果原地修改,这个索引就不是“有序”的了 +++++++++++++++++++ 我的问题是:即使是更新主键索引,把2 改成6 了,不是只要修改指针就可以保证有序了么? 为什么需要先删除,再插入一条数据 ? 这里对更新的流程不太熟悉,请老师稍微详细解答下。展开
作者回复: 可以这么想下,如果2 和 6应该属于不同的父亲节点,那父亲节点怎么表示这个page的取值范围?
共 5 条评论8 - 毛毛2018-12-12可能性有两个。 1. 生成临时表过程中,row log中新增的数据较多,导致表的行数变多。 2. 生成临时表过程中,row log中有部分插入和删除操作会产生“空洞”。 个人感觉,第一种情况,突然多了高于1%的数据,比较少见;但第二种情况,在某些业务中,经常出现。9