专栏首页腾讯云数据库专家服务MySQL 案例:表空间碎片
原创

MySQL 案例:表空间碎片

背景

经常使用 MySQL 的话,会发现 MySQL 数据文件的磁盘空间一般会不停的增长,而且有时候删了数据或者插入一批数据的时候,磁盘空间有时候还会毫无变化。引发这个其妙现象的就是 MySQL 的表空间碎片。

什么是表空间碎片?

表空间碎片指的是表空间中存在碎片,形象一点来比喻的话,就像是一张 A4 纸,“表空间碎片”就像是把这张 A4 纸撕碎,再重新拼起来,各个碎片之间都会有一些缝隙存在,这些缝隙就是“表空间碎片”。重新拼起来的碎片实际上会比完整的 A4 纸大上一圈,这也代表着表空间容易引发的问题:空间浪费

对于背景中描述的现象,可以用一张图来进行解释:

示例图

图中的数字代表真实的数据行,圆角矩形代表一个表的表空间。从左往右,第一次操作是删除数据,由于 MySQL 在设计上是不会主动释放空间的,因此当表中的数据行被删除时,虽然数据被“删除”了,但是实际上这部分空间是没有释放的,依旧会被 Table A 占用,因此也就出现了这样子的情景:删除了日志表的很多数据,但是 MySQL 的磁盘空间并没有降低

PS:这种不释放空间的设计多半和惰性删除有关,早期设计数据库时,使用的 IO 设备一般是机械盘,读写性能比 SSD 差很多,所以删除操作一般不会直接触发磁盘上的数据删除。

可以看到数据删除之后,原本连续的空间中出现了两个空白的区域,这种一般就叫做表空间空洞,空洞太多了就叫做表空间碎片化(对应的是表空间连续)。这部分的空间虽然不会释放,但是会被标记为可重复利用,参考最右边的表空间示意图(第三个圆角矩形),当新插入数据的时候新数据会重新写入到表空间空洞中,这也代表着:在大规模删除过数据的表上,写入数据时,表空间可能不会明显增长或者不会增长

实际上产生表空间空洞的操作并不只有 delete,update 也会引起这个问题,比如在 varchar 这种变长的字符型列中修改数据,改短一些的时候就会出现非常小的空洞,改长的话就有可能会因为空间不足导致把数据行的一些数据迁移到其他地方去。

怎么查看表空间碎片

MySQL 的系统表记录了表空间的使用情况,可以用如下查询检查:

SELECT CONCAT(table_schema,'.',table_name) AS 'table_name',
                table_rows AS 'Number of Rows',
                CONCAT(ROUND(data_length/(1024*1024),2),' M') AS 'data_size',
                CONCAT(ROUND(index_length/(1024*1024),2),' M') AS 'index_size' ,
                CONCAT(ROUND(data_free/(1024*1024),2),' M') AS'data_free',
                CONCAT(ROUND(data_free/data_length,2),' %') AS 'data_free_pct',
                ENGINE as 'engine'
FROM information_schema.TABLES
WHERE table_schema = 'tablename' 
ORDER by data_free desc;

data_free 指表空间碎片的总空间大小,data_free_pct 指这个表的碎片百分比,效果如下:

mysql> SELECT CONCAT(table_schema,'.',table_name) AS 'table_name',
    ->                 table_rows AS 'Number of Rows',
    ->                 CONCAT(ROUND(data_length/(1024*1024),2),' M') AS 'data_size',
    ->                 CONCAT(ROUND(index_length/(1024*1024),2),' M') AS 'index_size' ,
    ->                 CONCAT(ROUND(data_free/(1024*1024),2),' M') AS'data_free',
    ->                 CONCAT(ROUND(data_free/data_length,2),' %') AS 'data_free_pct',
    ->                 ENGINE as 'engine'
    -> FROM information_schema.TABLES
    -> WHERE table_schema = 'sbtest'
    -> ORDER by data_free desc;
+----------------+----------------+-----------+------------+-----------+---------------+--------+
| table_name     | Number of Rows | data_size | index_size | data_free | data_free_pct | engine |
+----------------+----------------+-----------+------------+-----------+---------------+--------+
| sbtest.sbtest5 |              0 | 0.02 M    | 0.00 M     | 44.00 M   | 2816.00 %     | InnoDB |
| sbtest.sbtest4 |         986400 | 214.70 M  | 15.52 M    | 4.00 M    | 0.02 %        | InnoDB |
| sbtest.sbtest3 |         986400 | 214.70 M  | 15.52 M    | 4.00 M    | 0.02 %        | InnoDB |
| sbtest.sbtest2 |         986400 | 214.70 M  | 15.52 M    | 4.00 M    | 0.02 %        | InnoDB |
| sbtest.sbtest1 |         987400 | 199.70 M  | 15.52 M    | 4.00 M    | 0.02 %        | InnoDB |
+----------------+----------------+-----------+------------+-----------+---------------+--------+
5 rows in set (0.00 sec)

第一行数据是测试用的数据,表中的所有数据都被删掉了,因此计算出来的 data_free_pct 超过了 100%。

怎么解决表空间碎片问题

目前,能够回收表空间的办法仅有一个,就是重建表,手段包括但不限于 optimize,alter table 等。alter table 的有些操作只能靠 rebuild 表来完成,所以有时候对大表进行一些维护操作之后,也会看到磁盘空间使用率下降,这就是回收了表空间碎片腾出来的那一部分空间。

从一般经验来看,表空间碎片的回收操作不建议经常执行,每个月一次就足够了,因为 rebuild 表对服务器的资源影响会比较大,且会影响这个表的写入操作。碎片率(data_free_pct)低于 20% 的时候也不用特别在意,除非磁盘空间非常紧张,且日志基本被清空。

对于回收空间的问题

对一些日志表,或者是有区域性特征的表,建议使用 MySQL 的分区表来管理,需要清理一批数据的时候,可以用 partition truncate 的方式进行清理,磁盘空间也能直接释放掉。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • MySQL 清除表空间碎片

    (1)表的存储会出现碎片化,每当删除了一行内容,该段空间就会变为空白、被留空,而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大...

    Java后端技术
  • MySQL 清除表空间碎片

    表的存储会出现碎片化,每当删除了一行内容,该段空间就会变为空白 当执行插入操作时,MySQL会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用...

    dys
  • 小白学习MySQL - 表空间碎片整理方法

    《小白学习MySQL - MySQL会不会受到“高水位”的影响?》曾提到了MySQL中数据删除的空间清理和文件释放的问题。碰巧看到姚老师这篇文章,《MySQL表...

    bisal
  • 技术分享 | MySQL 表空间碎片整理方法

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

    爱可生开源社区
  • 【迪B课堂】MySQL表空间碎片产生原因和优化

    点击上方蓝字每天学习数据库 【迪B课堂】为腾讯云数据库产品经理迪B哥开设的面向数据库开发者、数据库运维人员、云端运维人员的系列培训课程,旨在帮助大家从入门到精...

    腾讯云数据库 TencentDB
  • MySQL之表碎片简介

    对于mysql和Infobright等数据库,information_schema数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加触发器,因为...

    AsiaYe
  • Innodb页合并和页分裂

    如果您遇到全球少数的MySQL顾问之一,请他审核您的SQL语句和表结构设计,我相信他会告诉您一些有关好的主键设计的重要性。特别是对InnoDB,我相信他已经想您...

    老叶茶馆
  • MySQL Case-MySQL表碎片整理方法

    做为Oracle DBA在日常的数据库维护中,在给客户制定维护方案时,都会有降低高水位此类的建议

    姚崇
  • 如果mysql磁盘满了,会发生什么?还真被我遇到了!

    网上查了很多资源,说要进行磁盘碎片化整理。原因是datafree占据的空间太多啦。具体可以通过这个sql查看。

    良月柒
  • 如果mysql磁盘满了,会发生什么?

    网上查了很多资源,说要进行磁盘碎片化整理。原因是datafree占据的空间太多啦。具体可以通过这个sql查看。

    良月柒
  • 记一次 mysql 磁盘满解决过程

    网上查了很多资源,说要进行磁盘碎片化整理。原因是datafree占据的空间太多啦。具体可以通过这个sql查看。

    趣学程序-shaofeer
  • mysql 性能优化方案 (转)

    网 上有不少mysql 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与复杂,同样的设置,在不同的环境下 ,由于内存,访问量,读写频...

    wangxl
  • MySQL优化方案(一)优化SQL脚本与索引

    MySQL的优化方案有哪一些? 本文记录MySQL优化方案 ,梗概如下: 优化SQL 优化索引 (一)优化SQL 1、通过MySQL自有的优化语句 优化SQL语...

    赵腰静
  • 每日一面 - mysql 大表批量删除大量数据

    删除一条记录,首先锁住这条记录,数据原有的被废弃,记录头发生变化,主要是打上了删除标记。也就是原有的数据 deleted_flag 变成 1,代表数据被删除。但...

    干货满满张哈希
  • 一次生产环境mysql迁移操作(二)mysql空间释放(碎片整理)

    上文中增加了定时归档,现在一些大表磁盘空间一直不释放,导致数据库文件越来越大。现在介绍下数据导入导出方案。

    一笠风雨任生平
  • 计算MySQL表碎片的SQL整理

    当然整理的过程不光是知识梳理的过程,也是转化为实践场景的一个过程,通过这样一个体系,对于整个MySQL对象生命周期管理有了较为深入的认识,这里我来抛砖引玉,来作...

    jeanron100
  • MySQL InnoDB 共享表空间和独立表空间

    导读:深入学习MySQL的时候总是习惯性的和Oracle数据库进行比较。在学习MySQL InnoDB的存储结构的时候也免不了跟Oracle进行比较。Oracl...

    码农架构
  • 小弟问我:为什么MySQL不建议使用delete删除数据?

    我负责的有几个系统随着业务量的增长,存储在MySQL中的数据日益剧增,我当时就想现在的业务方不讲武德,搞偷袭,趁我没反应过来把很多表,很快,很快啊都打到了亿级别...

    敖丙
  • 2020-12-29:mysql中,innodb表里,某一条数据删除条数据会

    2020-12-29:mysql中,innodb表里,某一条数据删除了之后,这条数据会被真实的擦掉吗,还是删除了关系?

    福大大架构师每日一题

扫码关注云+社区

领取腾讯云代金券