您好,欢迎访问一九零五行业门户网

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

本篇文章给大家带来了关于mysql的相关知识,其中主要整理了解决delete大量数据后空间不释放的相关问题,mysql 中 insert 与 update 都可能导致页分裂,这样就存在碎片,下面一起来看一下,希望对大家有帮助。
推荐学习:mysql视频教程
   mysql 的几种碎片整理方案总结(解决delete大量数据后空间不释放的问题)1.背景知识?1.1 为什么会有碎片?mysql 中 insert 与 update 都可能导致页分裂,这样就存在碎片。
对于大量的update,也会产生文件碎片化 , innodb的最小物理存储分配单位是页(page),而update也可能导致页分裂(page split),频繁的页分裂,页会变得稀疏,并且被不规则的填充,所以最终数据会有碎片。
delete 语句实际上只是给数据打个标记,并且记录到一个链表中,这样就形成了留白空间。
在innodb中,删除一些行,这些行只是被标记为“已删除”,而不是真的从索引中物理删除了,因而空间也没有真的被释放回收。innodb的purge线程会异步的来清理这些没用的索引键和行。
当执行插入操作时,mysql会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片;
总结:
表的增删改操作,可能会造成数据空洞的,当对表进行大量的增删改操作后,数据空洞存在的可能性比较大。
mysql删除数据几种情况以及是否释放磁盘空间:
drop ,truncate 立刻释放磁盘空间 ,不管是 innodb和myisam ;truncate table其实有点类似于drop table 然后creat,只不过这个create table 的过程做了优化,比如表结构文件之前已经有了等等。所以速度上应该是接近drop table的速度;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表以后虽然未释放磁盘空间,但是下次插入数据的时候,仍然可以使用这部分空间。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_freefrom `information_schema`.tableswhere 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-oscpt-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视频教程
以上就是mysql怎么解决delete大量数据后空间不释放的问题的详细内容。
其它类似信息

推荐信息