MySQL如何解决delete大量数据后空间不释放的问题

37次阅读
没有评论

共计 6435 个字符,预计需要花费 17 分钟才能阅读完成。

本篇内容主要讲解“MySQL 如何解决 delete 大量数据后空间不释放的问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“MySQL 如何解决 delete 大量数据后空间不释放的问题”吧!

MySQL 的几种碎片整理方案总结(解决 delete 大量数据后空间不释放的问题)1. 背景知识?1.1 为什么会有碎片?

MySQL 中 insert 与 update 都可能导致页分裂,这样就存在碎片。

对于大量的 UPDATE,也会产生文件碎片化,Innodb 的最小物理存储分配单位是页(page),而 UPDATE 也可能导致页分裂(page split),频繁的页分裂,页会变得稀疏,并且被不规则的填充,所以最终数据会有碎片。

delete 语句实际上只是给数据打个标记,并且记录到一个链表中,这样就形成了留白空间。

在 InnoDB 中,删除一些行,这些行只是被标记为“已删除”,而不是真的从索引中物理删除了,因而空间也没有真的被释放回收。InnoDB 的 Purge 线程会异步的来清理这些没用的索引键和行。

当执行插入操作时,MySQL 会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片;

总结:

truncate table 其实有点类似于 drop table 然后 creat, 只不过这个 create table 的过程做了优化,比如表结构文件之前已经有了等等。所以速度上应该是接近 drop table 的速度;

drop,truncate 立刻释放磁盘空间,不管是 Innodb 和 MyISAM ;

delete from table_name 删除表的全部数据, 对于 MyISAM 会立刻释放磁盘空间(应该是做了特别处理,也比较合理),InnoDB 不会释放磁盘空间;

对于 delete from table_name where xxx; 带条件的删除, 不管是 innodb 还是 MyISAM 都不会释放磁盘空间;

delete 操作以后使用 optimize table table_name 会立刻释放磁盘空间。不管是 innodb 还是 myisam。所以要想达到释放磁盘空间的目的,delete 以后执行 optimize table 操作。

delete from 表以后虽然未释放磁盘空间,但是下次插入数据的时候,仍然可以使用这部分空间。

表的增删改操作,可能会造成数据空洞的,当对表进行大量的增删改操作后,数据空洞存在的可能性比较大。

MySQL 删除数据几种情况以及是否释放磁盘空间:

1.2 碎片带来的问题

当 MySQL 对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分;

MySQL 数据库中的表在进行了多次 delete、update 和 insert 后,表空间会出现碎片。定期进行表空间整理,消除碎片可以提高访问表空间的性能。

这种碎片不仅额外增加了存储代价,同时也因为数据碎片化降低了表的扫描效率。

碎片若不整理,那么可能会长期占据磁盘空间,导致磁盘使用率越来越高。

2. 如何清理碎片?

修复问题的前提是要先找到问题,这样才能对症下药。

2.1. 查看表的碎片情况

查看数据库中每个存在碎片的表

mysql  select concat(optimize table  ,table_schema, . ,table_name,),data_free,engine from information_schema.tables where data_free 0 and engine != MEMORY 
+-----------------------------------------------------------+-----------+--------+
| concat(optimize table  ,table_schema, . ,table_name,) | DATA_FREE | ENGINE |
+-----------------------------------------------------------+-----------+--------+
| optimize table abc.t_user_answer;  | 2097152 | InnoDB |
| optimize table mysql.time_zone_transition; | 4194304 | InnoDB |
| optimize table mysql.time_zone_transition_type; | 4194304 | InnoDB |
| optimize table mysql.user; | 4194304 | InnoDB |。。。。

查看指定表的碎片情况

 mysql  show table status like  t_user \G
 *************************** 1. row ***************************
 Name: t_user
 Engine: InnoDB
 Version: 10
 Row_format: Dynamic
 Rows: 4333
 Avg_row_length: 589
 Data_length: 2555904
 Max_data_length: 0
 Index_length: 2719744
 Data_free: 4194304
 Auto_increment: NULL
 Create_time: 2021-11-19 10:13:31
 Update_time: 2022-04-20 14:28:42
 Check_time: NULL
 Collation: utf8mb4_general_ci
 Checksum: NULL
 Create_options:
 Comment:
 1 row in set (0.00 sec)

 

Data_free: 4194304 就代表碎片的 byte 数。如果经常删改数据表,会造成大量的 Data_free 频繁 删除记录 或修改有可变长度字段的表。

找到碎片化最严重的表

SELECT table_schema, TABLE_NAME, concat(data_free/1024/1024,  M) as data_free
FROM `information_schema`.tables
WHERE data_free   3 * 1024 * 1024
 AND ENGINE =  innodb 
ORDER BY data_free DESC

2.2 清理碎片 (回收空间) 的方法

官方文档参考

通常有这几种做法

alter table tb_test engine=innodb;(本质上是 recreate)

optimize table tb_test;(本质上是 recreate,但是在不同创建下会有区别)

ALTER TABLE tablename FORCE (在 InnoDB 表中等价于 alter table tb_test engine=innodb;)

mysqlcheck 批量表空间优化

gh-ost/pt-osc

pt-online-schema-change(本质上也是 先备份旧表数据,然后 truncate 旧表)

1. alter table tb_test engine=innodb 原理介绍

这其实是一个 NULL 操作, 表面上看什么也不做, 实际上重新整理碎片了. 当执行优化操作时, 实际执行的是一个空的 ALTER 命令, 但是这个命令也会起到优化的作用, 它会重建整个表, 删掉未使用的空白空间.

Running ALTER TABLE tbl_name ENGINE=INNODB on an existing InnoDB table performs a“null”ALTER TABLE operation, which can be used to defragment an InnoDB table, as described in Section 15.11.4,“Defragmenting a Table”. Running ALTER TABLE tbl_name FORCE on an InnoDB table performs the same function.

 MySQL5.6  开始采用  Inplace  方式重建表,Alter  期间,支持  DML  查询和更新操作,语句为  alter table t engine=innodb, ALGORITHM=inplace; 之所以支持  DML  更新操作,是因为数据拷贝期间会将  DML  更新操作记录到  Row log  中。  重建过程中最耗时的就是拷贝数据的过程,这个过程中支持  DML  查询和更新操作,对于整个  DDL  来说,锁时间很短,就可以近似认为是  Online DDL。  执行过程: 1、获取  MDL(Meta Data Lock)写锁,innodb  内部创建与原表结构相同的临时文件
 2、拷贝数据之前,MDL  写锁退化成  MDL  读锁,支持  DML  更新操作
 3、根据主键递增顺序,将一行一行的数据读出并写入到临时文件,直至全部写入完成。并且,会将拷贝期间的  DML  更新操作记录到  Row log  中
 4、上锁,再将  Row log  中的数据应用到临时文件
 5、互换原表和临时表表名
 6、删除临时表

2. optimize table xxx;

OPTIMIZE TABLE 语句可以重新组织表、索引的物理存储,减少存储空间,提高访问的 I / O 效率。类似于碎片整理功能。

MySQL 可以通过 optimize table 语句释放表空间,重组表数据和索引的物理页,减少表所占空间和优化读写性能

使用语法

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_n 说 ame [, tbl_name] …

对于主从架构,LOCAL 参数可以让这个过程不写入 binlog , 这样在主库上执行时就不会同步给从库了

默认情况下,MySQL 将 OPTIMIZE TABLE 语句写入二进制日志,以便它们复制到 slave 服务器。如果不想写二进制日志,使用命令时加上 NO_WRITE_To_BINLOG 或 LOCAL 关键字即可。

使用这个语句需要具有对目标表的 SELECT、INSERT 权限。

注意:

需要有足够的空间才能进行 OPTIMIZE TABLE。(剩余空间必须 被 OPTIMIZE 的表的大小)

OPTIMIZE 只对独立表空间 (innodb_file_per_table=1) 才有用,对共享表空间不起作用。

对于共享表空间,如果需要瘦身:必须将数据导出,删除 ibdata1,然后将 innodb_file_per_table 设置为独立表空间,然后将数据导入进来。

对于 InnoDB 的表,OPTIMIZE TABLE 的工作原理如下

对于 InnoDB 表,OPTIMIZE TABLE 映射到 ALTER TABLE … FORCE(或者这样翻译:在 InnoDB 表中等价 ALTER TABLE … FORCE),它重建表以更新索引统计信息并释放聚簇索引中未使用的空间。

当您在 InnoDB 表上运行时,它会显示在 OPTIMIZE TABLE 的输出中,如下所示:mysql  OPTIMIZE TABLE foo; 
+----------+----------+----------+---------------------------------------+ 
| Table | Op | Msg_type | Msg_text | 
+----------+----------+----------+---------------------------------------+ 
| test.foo | optimize | note | Table does not support optimize, doing recreate + analyze instead | 
| test.foo | optimize | status | OK | 
+----------+----------+----------+---------------------------------------+ 
#  但这个提示语可以忽略,从严格的意义讲,说 InnoDB 不支持 optimize table,其实不太准确。  因为  MYSQL 的文档说明了,当 INNODB  的表,MYSQL 会以  ALTER TABLE force + analyze  去执行这个命令(相当于做了 recreate 和 analyze)。  所以最终还是会看到  OK  的状态。 
# https://stackoverflow.com/questions/30635603/what-does-table-does-not-support-optimize-doing-recreate-analyze-instead-me

对于 MYISAM 表,OPTIMIZE TABLE 的工作原理:
1. 如果表已删除或分隔行,就修复该表。
2. 如果索引页没有排序,就排序它们。
3. 如果表的统计信息不是最新的(而且修复不能通过对索引进行排序),就更新它们。

** 执行时也可以发现报错:Temporary file write failure. **

建议参考这片文章:
Mysql optimize table 时报错 Temporary file write failure. 的解决方案

optimize 语句的官网介绍

如果您已经删除了表的一大部分,或者如果您已经对含有可变长度行的表(含有 VARCHAR, BLOB 或 TEXT 列的表)进行了很多更改,则应使用 OPTIMIZE TABLE。

被删除的记录被保持在链接清单中,后续的 INSERT 操作会重新使用旧的记录位置。您可以使用 OPTIMIZE TABLE 来重新利用未使用的空间,并整理数据文件的碎片。

在多数的设置中,您根本不需要运行 OPTIMIZE TABLE。即使您对可变长度的行进行了大量的更新,您也不需要经常运行,每周一次或每月一次 即可,只对特定的表运行。

Mysql 5.6 之前 在 OPTIMIZE TABLE 运行过程中,MySQL 会锁定表,5.6 之后有了 Online DDL 则大大减少了锁表时间。

3. alter table、analyze table 和 optimize table 区别

alter table tb_test engine = innodb;

(也就是 recreate)MySQL 5.5 以前用 Offline 的方式重建表,5.6 以后用 Online 的方式重建表;

analyze table tb_test;

重新统计表的索引信息,不会修改数据,不会重建表,整个过程加 MDL 读

optimize table tb_test;

是 alter table xxx = innodb;+ analyze table xxx; 的过程。

4. OPTIMIZE TABLE 和 ALTER TABLE xxxx ENGINE= INNODB 哪个更好

OPTIMIZE TABLE 还是 ALTER TABLE xxxx ENGINE= INNODB 基本上是一样的。但是在有些情况下,ALTER TABLE xxxx ENGINE= INNODB 更好。

例如: old_alter_table 系统变量没有启用等等。

另外:对于 MyISAM 类型表,使用 ALTER TABLE xxxx ENGINE= INNODB 是明显要优于 OPTIMIZE TABLE 这种方法的。

2.3 官方建议

MySQL 官方建议不要经常 (每小时或每天) 进行碎片整理,一般根据实际情况,只需要每周或者每月整理一次即可(我们现在是每月凌晨 4 点清理 mysql 所有实例下的表碎片)

到此,相信大家对“MySQL 如何解决 delete 大量数据后空间不释放的问题”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计6435字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)