MySQL之表碎片化

文章目录

    • 1. 前言
    • 2. InnoDB表碎片
    • 3. 清除表碎片
      • 3.1 查找碎片化严重的表
      • 3.2 清除碎片
    • 4. 小结
    • 5. 参考

1. 前言

周一在对线上表进行数据清除时,发现一个问题,我要清除的单表大概有2500w条数据,清除数据大概在1300w条左右,清除之前通过查询语句获取到的表大小约为7000MB。

SELECT table_name as Table, round(((data_length + index_length) / 1024 / 1024), 5) as Size(MB) FROM information_schema.tables WHERE table_schema ='db_name' AND table_name = 'table_name'\G

通过脚本清除之后,再通过查询语句获取表大小,发现表仍然有6000MB的数据剩余。感觉肯定是有对应的一些索引数据没有被删除掉,仍然保存在表中,导致表空间仍然很大。

后面了解到这个是MySQL的数据碎片,加上使用的是MySQL的InnoDB引擎,导致即使我们删除数据,表空间也不会缩小,需要通过一些额外的表优化手段来清除这些数据碎片,因为用的是InnoDB引擎,所以就看了下关于InnoDB引擎表碎片相关的知识。

2. InnoDB表碎片

InnoDB表的数据存储在页(page)中,每个页可以存放多条记录,InnoDB默认使用B+树作为索引结构,表中的数据和辅助索引都是使用B+树结构,每个InnoDB表中都有一个称为聚簇索引的特殊索引,用于存储行数据。通常聚簇索引与主键索引同义。

通过聚簇索引访问行的速度很快,以为索引搜索会直接找到包含行数据的页面,如果表很大,与使用与索引记录不同的页面存储行数据的存储组织相比,聚簇所以架构通常可以节省磁盘I/O操作。

除了聚簇索引之外,还有一个二级索引,我们也叫做辅助索引。在InnoDB中,辅助索引中的每个记录都包含行的主键列以及为二级索引指定的列,InnoDB使用此主键值在聚簇索引中搜索行。如果主键很长,则辅助索引将使用更多的空间,因此使用较短的主键是比较好的。

对于InnoDB而言,随机插入或者删除辅助索引可能会导致索引碎片化,碎片化意味着磁盘上索引页的物理顺序与页面上记录的索引顺序不接近,或者分配给索引的64页块中有许多未使用的页面。

**碎片的一个症状是表占用的空间比它“应该”占用的空间要多,**具体会多多少很难确定。所有InnoDB数据和索引都存储在B树种,它们的填充因子可能从50%到100%不等。碎片的另一个症状是表扫描花费的时间比它“应该”花费的时间要多

在InnoDB中,删除一些行,InnoDB并不会真正的删除它们,只是会将这些行标记为“已删除”(同时也称为可复用的位置,即后续如果有对应的主键数据插在这段区域,会复用位置),而不是真的从索引中物理删除,因此存储空间也没有真的被释放。

删除数据会导致页中出现空白空间,大量随机的DELETE操作会在数据文件中造成不连续的空白空间,当插入数据的时候,这些可复用的空白空间会被利用起来,但这会造成数据存储位置的不连续,即物理存储顺序与逻辑上的排序顺序不同,于是就产生了表数据碎片。

对表进行大量的UPDATE操作也可能会导致页分裂,频繁地页分裂,页会变得稀疏,并且被不规则的填充,继而产生表碎片,

另外,表的数据存储也可能会碎片化,数据存储的碎片化比索引更加复杂,主要有三种类型的数据碎片:

  1. 行碎片(Row fragmetation)
    1. 指数据行被存储在多个地方的片段中,即使查询只从索引中访问一行记录,行碎片也会导致性能下降
  2. 行间碎片(Intra-row fragmetaion)
    1. 行间碎片是指逻辑上顺序的页或者行在磁盘上不是顺序存储的,行间碎片对诸如全表扫描和聚簇索引扫描之类的操作有很大的影响,因为这些操作原本能从磁盘顺序存储的数据中获益
  3. 剩余空间碎片(Free space fragmenation)
    1. 指数据页中有大量的空余空间,会导致服务器读取大量不需要的数据,从而造成浪费。

对于MyISAM表,上述三类碎片化都有可能发生,但InnoDB不会出现短小的行碎片,InnoDB会移动短小的行并重写到一个片段中。

3. 清除表碎片

删除了数据而空间没有得到释放,于是我们需要采取一些手段来清除删除的数据留下的表碎片,从而释放存储空间,同时提升查询效率。

3.1 查找碎片化严重的表

对于表中是否含有碎片,可以通过下面的命令直接查看表信息。

show table status from db_name like '%table_nam%'\G
mysql> show table status like '%user_tab%'\G
*************************** 1. row ***************************Name: user_tabEngine: InnoDBVersion: 10Row_format: DynamicRows: 4   -- 可以看到有4行数据Avg_row_length: 4096Data_length: 16384
Max_data_length: 0Index_length: 16384Data_free: 0  -- 可释放的空间为0Auto_increment: 5Create_time: 2023-08-12 16:58:07Update_time: 2024-06-23 16:38:08Check_time: NULLCollation: utf8_general_ciChecksum: NULLCreate_options: Comment: 
-- 插入一些数据,然后看Data Free,发现有许多可释放的数据       
mysql> show table status like 'user_tab'\G
*************************** 1. row ***************************Name: user_tabEngine: InnoDBVersion: 10Row_format: DynamicRows: 351Avg_row_length: 10502Data_length: 3686400
Max_data_length: 0Index_length: 1589248Data_free: 9437184Auto_increment: 41282Create_time: 2023-08-12 16:58:07Update_time: 2024-06-23 17:00:29Check_time: NULLCollation: utf8_general_ciChecksum: NULLCreate_options: Comment: 
1 row in set (0.00 sec)

3.2 清除碎片

清理碎片主要有两种方式:

第一种是优化表,即OPTIMIZE TABLE,这种方式会重组表和索引的物理存储,减少对存储空间的使用和提升访问表的I/O效率。OPTIMIZE操作会暂时锁住表,数据量越大,则耗时越长。对每个表所做的确切更改取决于该表使用的存储引擎。

对于InnoDB表,OPTIMIZE TABLE会映射到ALTER TABLE … FORCE, 这将重建表以更新索引统计信息并释放聚簇索引中未使用的空间。

对刚刚的user_tab采用OPTIMIZE的命令,可以看到空间被释放了。

mysql> optimize table user_tab\G
*************************** 1. row ***************************Table: duanxi.user_tabOp: optimize
Msg_type: note
Msg_text: Table does not support optimize, doing recreate + analyze instead
-- 实际采用的事recreate + analyze方式
*************************** 2. row ***************************Table: duanxi.user_tabOp: optimize
Msg_type: status
Msg_text: OK
2 rows in set (0.04 sec)mysql> show table status like 'user_tab'\G
*************************** 1. row ***************************Name: user_tabEngine: InnoDBVersion: 10Row_format: DynamicRows: 7Avg_row_length: 2340Data_length: 16384
Max_data_length: 0Index_length: 16384Data_free: 0   -- 优化后Data Free变为0了Auto_increment: 41282Create_time: 2024-06-23 17:02:48Update_time: NULLCheck_time: NULLCollation: utf8_general_ciChecksum: NULLCreate_options: Comment: 
1 row in set (0.00 sec)

InnoDB的OPTIMIZE TABLE对常规表和分区表使用在线DDL方式,从而减少并发DML操作的停机时间。由OPTIMIZE TABLE触发的表重建会在原地完成,在操作的准备阶段和提交阶段,只短暂地采用排它表锁,在准备阶段,更新元数据并创建中间表,在提交阶段,提交表元数据更改。

在线DDL(MySQL 8.0+)
在线 DDL 功能支持即时、就地表更改和并发 DML。此功能的优点包括:

  • 在繁忙的生产环境中提高响应能力和可用性,因为让表不可用几分钟或几小时是不切实际的。
  • 对于就地操作,可以使用LOCK子句在 DDL 操作期间调整性能和并发之间的平衡。
  • 与表复制方法相比,磁盘空间使用量和 I/O 开销更少。

OPTIMIZE TABLE在以下情况下使用表赋值方法重建表

  • old_alter_table系统变量启用时
  • 当服务器使用—skip-new选项启动时

InnoDB使用页面分配方法存储数据,不会像传统存储引擎(例如MyISAM)那样收到碎片的影响,在考虑是否运行优化时,请考虑你的服务器预计要处理的事务的工作负载。

  • 预计会出现一定程度的碎片,InnoDB仅填充93%的页面,以便留出更新空间,而无需拆分页面
  • 删除操作可能会留下空隙,导致页面填充不足,这可能会使优化表变得有价值
  • 当有足够的空间时,对行的更新通常会重写同一页内的数据,具体取决于数据类型和行格式。
  • 高并发工作负载可能会随着时间的推移在索引中留下空白,因为InnoDB通过其MVCC机制保留了同一数据的多个版本。

对于MyISAM,OPTIMIZE TABLE工作原理如下:

  1. 如果表有删除或拆分行,则修复该表。
  2. 如果索引页未排序,则对其进行排序。
  3. 如果表的统计信息不是最新的(并且无法通过对索引进行排序来完成修复),则更新它们。

第二种操作则是使用ALTER TABLE table_name ENGINE= InnoDB; 的方式,此方式看起来没有执行什么操作,实际上重新整理碎片了,当执行这个优化操作时,InnoDB会重建整个表并释放聚簇索引中未使用的空间。

4. 小结

因为删除表数据发现表使用空间未被释放,继而发现有表碎片问题,查找一些资料去了解表碎片的产生以及表碎片的处理,最终让自己学习到了关于InnoDB表碎片相关的知识。

表碎片的产生主要是InnoDB删除非物理删除,而是标记”删除”,且这些被“删除”的空间后续还可复用,进而导致磁盘上索引页的物理顺序与页面上记录的索引顺序不接近,引发表的碎片化。同时表的大量更新、表的数据存储页都会产生不同的表碎片。

表碎片的清除手段:

  1. OPTIMIZE TABLE table_name;
  2. ALTER TABLE table_name ENGINE = InnoDB;

需要注意的是,无论我们采用哪种手段清除表碎片,都会有锁表的时间,我们需要根据自己服务器要处理的事务的工作负载分析,研判这种锁表时间对于业务是否接受,如果可以接受则可以对表碎片进行优化,如果不能接受,则无需进行优化,等待后续再进行优化。(思考再三,我选择放弃优化,让碎片继续留在表中)

5. 参考

  • Defragmenting a Table
  • Overview of fragmented MySQL InnoDB tables
  • OPTIMIZE TABLE Statement

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网格处理库 pmp-library 编译及应用笔记 -- 已全部解决√

多边形网格处理库Polygon Mesh Processing Library,简称pmp-library的 编译及应用笔记 – 已全部解决√ 官网:https://www.pmp-library.org/index.html 代码:https://github.com/pmp-library/pmp-library 平台:Ubuntu1 20.04&…

Bandzip:打破压缩界限,文件管理更高效

名人说::一点浩然气,千里快哉风。 ——苏轼 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、软件介绍1、Bandzip2、核心特点 二、下载安装1、下载2、安装 三、使用方法 很高兴…

C语言中操作符详解(二)

OK,今天继续为诸君带来有关C语言中操作符的讲解 一 . 位操作符 C语言中的位操作符我相信大家并不陌生,我们在之前就已经接触过了一些 位操作符(位操作符的操作数只能是整数): (1)& &…

Origin较好用的科研绘图软件

推荐自己也在用的科研绘图软件Origin图所示: 图1 图2 图3

WMS项目测试点

这里写目录标题 最后附有图片 仓库系统 仓库 / 库区 仓库 新增仓库 编号 必填校验 字段长度校验 20为字符 数据类型校验 名称 必填校验 字段长度校验 20为字符 数据类型校验 备注 填写备注校验 字符长度限制 不填写备注校验 新增仓库之后是否可以通过查询仓库名称和仓库编号查询…

poi生成的excel,输入数字后变成1.11111111111111E+23

poi版本4.1.2 生成excel后,单元格输入数字,过长的话变成这样 解决:生成的时候设置单元格格式为文本格式 import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.FileOutputStream; imp…

数据结构与算法笔记:基础篇 - 初始动态规划:如何巧妙解决“双十一”购物时的凑单问题?

概述 淘宝的 “双十一” 购物节有各种促销活动,比如 “满 200 元减 50元”。假设你女朋友购物车中有 n 个(n > 100)想买的商品,它希望从里面选几个,在凑够满减条件的前提下,让选出来的商品价格总和最长…

学习笔记——路由网络基础——路由转发

六、路由转发 1、最长匹配原则 最长匹配原则 是支持IP路由的设备默认的路由查找方式(事实上几乎所有支持IP路由的设备都是这种查找方式)。当路由器收到一个IP数据包时,会将数据包的目的IP地址与自己本地路由表中的表项进行逐位(Bit-By-Bit)的逐位查找,…

一元线性回归模型 多元线性回归模型回归模型评估

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

Vue41 ref属性

ref属性 ref是Vue提供的获取组件的属性 <template><div><h1 v-text"msg" ref"title"></h1><button ref"btn" click"showDOM">点我输出上方的DOM元素</button><MySchool ref"sch"…

若依微服务项目09 - swagger如何不显示某个模块的接口文档

在若依微服务项目中&#xff0c;如果不想暴露某个模块的swagger的接口文档&#xff0c;需要怎么做&#xff1f; 本文以ruoyi-gen模块进行举例说明。 默认情况下&#xff0c;可以看到这里包含了ruoyi-gen模块&#xff0c;我们要做的是&#xff0c;要将ruoyi-gen进行隐藏。 最终的…

阐述Spring Security概念及其运用于实战

Spring Security(安全校验) 1. 概述 Spring Security是Spring项目组提供的安全服务框架,核心功能包括认证和授权.为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作. 在如今开发模式中,Spring Security已经成为Java程序员必备的一项技术,简化认证…

5 DSL入门_02精确查询

1. 精确查询 (1)一般是查找keyword,数值&#xff0c;日期&#xff0c;boolean等类型字段&#xff0c;所以不会对搜索条件分词&#xff0c;常见的有&#xff1a;term,range//只查询city南京市鼓楼区,且不会对搜索词分词 get /hotel/_search {"query":{"term&quo…

RabbitMQ实战宝典:从新手到专家的全面探索

前言 在当今分布式系统架构中&#xff0c;消息队列已成为不可或缺的一部分&#xff0c;而RabbitMQ作为其中的佼佼者&#xff0c;凭借其强大的功能和灵活性&#xff0c;广泛应用于各种规模的应用场景中。本文将带你从基础概念出发&#xff0c;深入探讨RabbitMQ的核心特性&#…

计算机网络 静态路由及动态路由RIP

一、理论知识 1.静态路由 静态路由是由网络管理员手动配置在路由器上的固定路由路径。其优点是简单和对网络拓扑变化不敏感&#xff0c;缺点是维护复杂、易出错&#xff0c;且无法自动适应网络变化。 2.动态路由协议RIP RIP是一种基于距离向量的动态路由协议。它使用跳数作…

springboot+vue+mysql+mybatis 二手交易平台

springbootvuemysqlmybatis 二手交易平台 相关技术 javaspringbootmybatismysqlvueelementui

芯片后端之 PT 使用 report_timing 产生报告如何阅读

今天,就PT常用的命令,做一个介绍,希望对大家以后的工作,起到帮助作用。 在PrimeTime中,使用report_timing -delay max命令生成此报告。switch -delay max表示定时报告用于设置(这是默认值)。 首先,我们整体看一下通过report_timing 运行之后,报告产生的整体样式。 pt…

Bootstrap 5 导航

Bootstrap 5 导航 Bootstrap 5 是一个流行的前端框架&#xff0c;用于快速开发响应式和移动设备优先的网站。在本文中&#xff0c;我们将深入探讨 Bootstrap 5 中的导航组件&#xff0c;包括其功能、自定义选项以及如何在实际项目中有效使用它们。 简介 Bootstrap 5 的导航组…

vscode用vue框架2,续写登陆页面逻辑,以及首页框架的搭建

目录 前言&#xff1a; 一、实现登录页信息验证逻辑 1.实现登录数据双向绑定 2.验证用户输入数据是否和默认数据相同 补充知识1&#xff1a; 知识点补充2&#xff1a; 二、首页和登录页之间的逻辑(1) 1. 修改路由&#xff0c;使得程序被访问先访问首页 知识点补充3&am…

numpy.ndarray数据计算及操作集锦

目录 1. numpy.ndarray各列求均值1.1 列1.2 行 1. numpy.ndarray各列求均值 1.1 列 要对 v_sec_trans 数组的每一列求均值&#xff0c;可以使用 numpy 库中的 mean 函数。以下是具体的代码示例&#xff1a; import numpy as np# 定义 v_sec_trans 数组 v_sec_trans np.array…