当前位置:

首页 > 编程开发 > MySQL如何解决长时间运行DELETE语句导致空间不释放的问题?

MySQL如何解决长时间运行DELETE语句导致空间不释放的问题?

MySQL的几种碎片整理方案总结(解决delete大量数据后空间不释放的问题)1.背景知识?1.1为什么会有碎片?MySQL中insert与update都可能导致页分裂,这样就存在碎片。对于大量的UPDATE,也会产生文件碎片化,Innodb的最小物理存储分配单位是页(page),而UPDATE也可能导致页分裂(pagesplit),频繁的页分裂,页会变得稀疏,并且被不规则的填充,所以最终数据会有碎片。delete语句实际上只是给数据打个标记,并且记录到一个链表中,这样就形成了留白空间。在InnoDB中,

本文目录

    MySQL如何解决长时间运行DELETE语句导致空间不释放的问题?

    MySQL 的几种碎片整理方案总结(解决delete大量数据后空间不释放的问题)

    1.背景知识?

    1.1 为什么会有碎片?

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

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

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

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

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

    4. 总结:

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

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

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

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

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

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

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

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

    1.2 碎片带来的问题

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

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

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

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

    2. 如何清理碎片?

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

    2.1. 查看表的碎片情况

    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 |
      。。。。
    2. 查看指定表的碎片情况

       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 频繁 删除记录 或修改有可变长度字段的表。

    3. 找到碎片化最严重的表

      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 清理碎片(回收空间)的方法

    官方文档参考
    MySQL如何解决长时间运行DELETE语句导致空间不释放的问题?

    通常有这几种做法
    1. alter table tb_test engine=innodb; (本质上是 recreate)

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

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

    4. mysqlcheck 批量表空间优化

    5. gh-ost/pt-osc

    6. 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语句释放表空间,重组表数据和索引的物理页,减少表所占空间和优化读写性能

    1. 使用语法

      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权限。

    2. 注意:

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

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

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

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

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

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

    3. optimize 语句的官网介绍

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

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

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

    4. 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所有实例下的表碎片)

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 MySQL delete
    相关文章 更多
    navicat导入数据库步骤详解及常见问题处理教程
    navicat导入数据库步骤详解及常见问题处理教程

    详解Navicat导入数据库的标准步骤,涵盖SQL脚本执行与CSV数据导入两种核心场景。针对导入过程中常见的字符集乱码、主键冲突及外键约束错误,提供具体的设置方法与修复建议,确保数据迁移准确无误。

    SQL主键约束和唯一约束有什么区别
    SQL主键约束和唯一约束有什么区别

    深入理解SQL PRIMARY KEY与UNIQUE约束的区别。文章从行标识与重复限制的目标出发,详解主键的非空特性、外键引用角色以及多数据库对NULL值的处理差异。结合users表实战示例,指导开发者如何根据字段稳定性与业务语义合理选择约束类型,避免设计误区。

    SQL约束有哪些类型及作用
    SQL约束有哪些类型及作用

    刚开始设计关系型数据库?了解PRIMARY KEY、FOREIGN KEY、UNIQUE、NOT NULL、CHECK、DEFAULT等约束的作用、语法和排错方法。本文以PostgreSQL语法为主,结合用户订单场景,清晰展示如何防止脏数据并处理常见约束冲突。

    SQL增删改操作规范:INSERT、UPDATE与DELETE语句详解
    SQL增删改操作规范:INSERT、UPDATE与DELETE语句详解

    掌握SQL增删改核心规范:INSERT必须指定列清单以防结构变更错误;UPDATE和DELETE执行前务必通过SELECT确认WHERE条件范围;利用事务BEGIN/ROLLBACK机制实现误操作回滚。本文结合PostgreSQL语法与跨库差异,提供从语句编写到结果验证的完整安全操作流程,帮助开发者规避生产环境数据风险。

    SQL游标常见错误排查:死锁与资源未释放问题
    SQL游标常见错误排查:死锁与资源未释放问题

    深入解析SQL游标导致的死锁与资源未释放问题。通过PostgreSQL与MySQL语法对比,展示如何识别长事务持锁、分析锁等待链,并提供短事务提交、异常清理及批量处理的最佳实践,确保数据库连接与锁资源及时释放。

    SQL中怎么创建和删除约束
    SQL中怎么创建和删除约束

    后端开发者在维护数据库时,常需对现有表添加主键、唯一或外键约束。若直接执行ADD CONSTRAINT,往往因存量数据不合规导致报错。本文详解操作前的数据清洗步骤、标准SQL语法及MySQL等特殊写法,帮助你在生产环境安全完成结构变更。

    SQL分组统计查询:GROUP BY与HAVING子句用法示例
    SQL分组统计查询:GROUP BY与HAVING子句用法示例

    针对 SQL 初学者的分组统计实战指南。深入解析 GROUP BY 分组机制、WHERE 与 HAVING 的执行时机差异,以及 COUNT 函数对 NULL 值的处理逻辑。通过具体代码示例演示如何正确筛选聚合结果,并排查因 JOIN 连接导致的统计数据异常,提升报表准确性。

    SQL Server与MySQL游标基本语法及完整代码示例
    SQL Server与MySQL游标基本语法及完整代码示例

    本文详细对比SQL Server和MySQL中游标的基本用法。从DECLARE声明到FETCH遍历,再到CLOSE关闭与DEALLOCATE/Handler清理,解析两者在语法结构、变量接收及异常处理上的核心差异。通过标准代码示例展示如何安全使用游标,避免资源泄漏,适用于需要进行数据库存储过程开发或跨平台迁移的开发者。

    SQL多表连接区别:INNER JOIN与LEFT JOIN的使用场景
    SQL多表连接区别:INNER JOIN与LEFT JOIN的使用场景

    深入解析SQL中INNER JOIN与LEFT JOIN的核心区别。通过users和orders表实例,展示匹配行保留与NULL补位机制,重点讲解ON与WHERE子句中放置右表过滤条件的不同后果,提供防止LEFT JOIN退化的实战技巧及行数异常排查步骤。

    SQL CHECK约束的用法与取值范围限制
    SQL CHECK约束的用法与取值范围限制

    深入理解 SQL CHECK 约束在 PostgreSQL、MySQL 等数据库中的实现差异。文章通过订单业务场景,讲解如何定义单列范围与多列逻辑约束,分析 NULL 值对布尔条件的影响,并提供修改已有表结构时的安全操作建议,帮助开发者构建更健壮的数据完整性防线。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。