关于MySQL中表碎片化(Table Fragmentation)产生的原因:

简单总结一下,MySQL Engine不同,碎片化的原因可能也有所差别。这里没有深入理解、分析这些差别。此文仅以InnoDB引擎为主。总结如有不足或错误的地方,敬请指出。InnoDB表的数据存储在页(page)中,每个页可以存放多条记录。这些记录以树形结构组织,这颗树称为B+树索引。表中数据和辅助索引都是使用B+树结构。维护表中所有数据的这颗B+树索引称为聚簇索引,通过主键来组织的。聚簇索引的叶子节点包含行中所有字段的值,辅助索引的叶子节点包含索引列和主键列。

在InnoDB中,删除一些行,这些行只是被标记为“已删除”,而不是真的从索引中物理删除了,因而空间也没有真的被释放回收。InnoDB的Purge线程会异步的来清理这些没用的索引键和行。但是依然没有把这些释放出来的空间还给操作系统重新使用,因而会导致页面中存在很多空洞。如果表结构中包含动态长度字段,那么这些空洞甚至可能不能被InnoDB重新用来存新的行,因为空间空间长度不足。关于这个你可以参考博客Overview of fragmented MySQL InnoDB tables。另外,删除数据就会导致页(page)中出现空白空间,大量随机的DELETE操作,必然会在数据文件中造成不连续的空白空间。而当插入数据时,这些空白空间则会被利用起来.于是造成了数据的存储位置不连续。物理存储顺序与逻辑上的排序顺序不同,这种就是数据碎片。对于大量的UPDATE,也会产生文件碎片化 , Innodb的最小物理存储分配单位是页(page),而UPDATE也可能导致页分裂(page split),频繁的页分裂,页会变得稀疏,并且被不规则的填充,所以最终数据会有碎片。

表的数据存储也可能碎片化。然而数据存储的碎片化比索引更加复杂。有三种类型的数据碎片化。##下面部分内容摘自【高性能MySQL】##

行碎片(Row fragmentation)

这种碎片指的是数据行被存储为多个地方的多个片段。即使查询只从索引中访问一行记录。行碎片也会导致性能下降。

行间碎片(Intra-row fragmentaion)

行间碎片是指逻辑上顺序的页,或者行在磁盘上不是顺序存储的。行间碎片对诸如全表扫描和聚簇索引扫描之类的操作有很大的影响,因为这些操作原本能够从磁盘上顺序存储的数据中获益。

剩余空间碎片(Free space fragmentation)

        剩余空间碎片是指数据页中有大量的空余空间。这会导致服务器读取大量不需要的数据。从而造成浪费。对于MyISAM表,这三类碎片化都有可能发生。但InnoDB不会出现短小的行碎片;InnoDB会移动短小的行并写到一个片段中。InnoDb会移动短小的行并重写到一个片段中。

MySQL中如何找出碎片化严重的表

方法:查询information_schema.TABLES获取表的碎片化信息。

以下脚本可以直接使用

SELECT CONCAT(table_schema, '.', table_name)                   AS  TABLE_NAME,engine                                                  AS  TABLE_ENGINE ,table_type                                              AS  TABLE_TYPE,table_rows                                              AS  TABLE_ROWS,CONCAT(ROUND(data_length  / ( 1024 * 1024), 2), 'M')    AS  TB_DATA_SIZE ,CONCAT(ROUND(index_length / ( 1024 * 1024), 2), 'M')    AS  TB_IDX_SIZE ,CONCAT(ROUND((data_length + index_length ) / ( 1024 * 1024 ), 2), 'M')                        AS  TOTAL_SIZE,CASE WHEN  data_length =0 THEN 0ELSE  ROUND(index_length / data_length, 2) END     AS  TB_INDX_RATE,CONCAT(ROUND( data_free / 1024 / 1024,2), 'MB')           AS  TB_DATA_FREE ,CASE WHEN (data_length + index_length) = 0 THEN 0ELSE ROUND(data_free/(data_length + index_length),2) END                                                       AS  TB_FRAG_RATE
FROM information_schema.TABLES
ORDER BY data_free DESC;
SELECT CONCAT(table_schema, '.', table_name)                    AS  TABLE_NAME,engine                                                   AS  TABLE_ENGINE ,table_type                                               AS  TABLE_TYPE,table_rows                                               AS  TABLE_ROWS,CONCAT(ROUND(data_length  / ( 1024 * 1024), 2), 'M')     AS  TB_DATA_SIZE ,CONCAT(ROUND(index_length / ( 1024 * 1024), 2), 'M')     AS  TB_IDX_SIZE ,CONCAT(ROUND((data_length + index_length ) / ( 1024 * 1024 ), 2), 'M')                         AS  TOTAL_SIZE,CASE WHEN  data_length =0 THEN 0ELSE  ROUND(index_length / data_length, 2) END      AS  TB_INDX_RATE,CONCAT(ROUND( data_free / 1024 / 1024,2), 'MB')            AS  TB_DATA_FREE ,CASE WHEN (data_length + index_length) = 0 THEN 0ELSE ROUND(data_free/(data_length + index_length),2) END                                                        AS  TB_FRAG_RATE
FROM information_schema.TABLES
WHERE ROUND(DATA_FREE/1024/1024,2) >=50
ORDER BY data_free DESC;
SELECT TABLE_SCHEMA,TABLE_NAME ,ENGINE,ROUND(((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024), 2) AS SIZE_MB,ROUND(DATA_FREE/1024/1024,2) AS FREE_SIZ_MB
FROM information_schema.TABLES
WHERE DATA_FREE >=10*1024*1024
ORDER BY FREE_SIZ_MB DESC;

MySQL中如何减低表的碎片

在MySQL中,可以使用OPTIMIZE TABLE、ALTER TABLE XXXX ENGINE = INNODB这两种方法降低碎片,关于这两者的简单介绍如下:

OPTIMIZE TABLE

OPTIMIZE TABLE 会重组表和索引的物理存储,减少对存储空间使用和提升访问表时的IO效率。对每个表所做的确切更改取决于该表使用的存储引擎

OPTIMIZE TABLE的支持表类型:INNODB,MYISAM, ARCHIVE,NDB;它会重组表数据和索引的物理页,对于减少所占空间和在访问表时优化IO有效果。OPTIMIZE 操作会暂时锁住表,而且数据量越大,耗费的时间也越长。 (但是我试了一下,正常的插入和查询都是正常的,不知道是上面原因)

mysql 5.7 以上,或者是mysql8.0的,optimize table xxx会提示:OPTIMIZE TABLE: Table does not support optimize, doing recreate + analyze instead。
建议使用:ALTER TABLE xxxx ENGINE=InnoDB;ANALYZE TABLE xxxx; 进行操作,这也是官方推荐的表碎片优化操作。

ALTER TABLE table_name ENGINE = Innodb;

这其实是一个NULL操作,表面上看什么也不做,实际上重新整理碎片了.当执行优化操作时,实际执行的是一个空的 ALTER 命令,但是这个命令也会起到优化的作用,它会重建整个表,删掉未使用的空白空间.Running ALTER TABLEtbl_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 TABLEtbl_name FORCE on an InnoDB table performs the same function.

问题1:那么是用OPTIMIZE TABLE 还是ALTER TABLE xxxx ENGINE= INNODB好呢?

其实对于InnoDB引擎,ALTER TABLE xxxx ENGINE= INNODB是执行了一个空的ALTER TABLE操作。而OPTIMIZE TABLE等价于ALTER TABLE ... FORCE。 参考上面描述,在有些情况下,OPTIMIZE TABLE 还是ALTER TABLE xxxx ENGINE= INNODB基本上是一样的。但是在有些情况下,ALTER TABLE xxxx ENGINE= INNODB更好。例如old_alter_table系统变量没有启用等等。另外对于MyISAM类型表,使用ALTER TABLE xxxx ENGINE= INNODB是明显要优于OPTIMIZE TABLE这种方法的。

问题2:ALTER TABLE xxxx ENGINE= INNODB 表上的索引碎片会整理么

ALTER TABLE ENGINE= INNODB,会重新整理在聚簇索引上的数据和索引。如果你想用实验验证,可以对比执行该命令前后index_length的大小。

其它工具

网友建议使用pt工具或者gh-ost降低表的碎片化

参考资料:

【高性能MySQL】

https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html

https://dev.mysql.com/doc/refman/8.0/en/innodb-file-defragmenting.html

https://lefred.be/content/overview-of-fragmented-mysql-innodb-tables/

https://yq.aliyun.com/articles/41166

http://mysql.taobao.org/monthly/2015/08/05/

http://www.cnblogs.com/kerrycode/

MySQL表碎片化(Table Fragmentation)以及处理相关推荐

  1. 回收mysql表碎片_MySQL表碎片整理

    MySQL表碎片整理 1. 计算碎片大小 要整理碎片,首先要了解碎片的计算方法. 可以通过show table [from|in db_name] status like '%table_name%' ...

  2. mysql 碎片率_计算MySQL表碎片的SQL整理

    原标题:计算MySQL表碎片的SQL整理 这是学习笔记的第 2111 篇文章 在之前整理过一版MySQL的数据字典,整理了一圈,发现远比想象的复杂. 当然整理的过程不光是知识梳理的过程,也是转化为实践 ...

  3. MySQL表碎片整理

    MySQL表碎片整理 1. 计算碎片大小 2. 整理碎片 2.1 使用`alter table table_name engine = innodb`命令进行整理. 2.2 使用pt-online-s ...

  4. oracle 表碎片化处理,oracle数据库碎片化管理

    ******************************************************************************** 1.表空间碎片 *********** ...

  5. mysql表analyze,ANALYZE TABLE语句如何帮助维护MySQL表?

    MySQL查询优化器是MySQL服务器的重要组成部分,可为查询设置最佳的问题执行.对于特定查询,查询优化器使用存储的键分布和其他因素来确定执行联接时应联接表的顺序以及特定表应使用哪个索引. 但是,键分 ...

  6. mysql怎么把值更新成space,MySQL表的碎片整理和空间回收小结

    MySQL表碎片化(Table Fragmentation)的原因 关于MySQL中表碎片化(Table Fragmentation)产生的原因,简单总结一下,MySQL Engine不同,碎片化的原 ...

  7. mysql 表空间收缩_mysql表碎片清理和表空间收缩

    mysql表碎片清理和表空间收缩(即清理碎片后report_site_day.ibd文件磁盘空间减小,该方案基于独立表空间存储方式) OPTIMIZETABLE [tablename],当然这种方式只 ...

  8. Mysql 报错 The table ‘tablename‘ is full解决方案

    一.报错 今天测试区debug程序遇到如下报错,数据落库失败. mysql Caused by: java.sql.SQLException: The table 'tablename' is ful ...

  9. mysql 分区表优化_Sql优化之Mysql表分区

    一  分区表适用于以下场景 1:表非常大以至于无法全部放在内存中,或者只在标的最后部分有热点数据,其他均是历史数据 2:分区表的数据更容易维护.例如想批量删除大量数据可以使用清除整个分区的方式.另外还 ...

最新文章

  1. 如何判断你的数据集是否适合使用深度学习模型?如果数据量太小有什么解决办法?
  2. WinCE5.0中应用程序如何直接写屏
  3. python编程语法-Python基础及语法(十三)
  4. pyhton 把文字放入图片里_藏在京城老字号里的六道功夫菜!久违了!!
  5. mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明
  6. Android RecyclerView 性能优化总结
  7. 推荐 10 本好书,并送上 110 本!
  8. 使用C#删除一个字符串数组中的空字符串
  9. 这个神器火了,做个高大上的PPT演示竟然就这么简单!
  10. Java 算法 特殊的数字四十
  11. 闲鱼:3月24日至3月30日冻结涉欺诈用户1.8万个
  12. 『转』图解硬件特性!
  13. scala Tuple入门到熟悉
  14. 破解工具之调试器和相关破解案例视频教程大全
  15. matlab 大数阶乘,紧急求助:怎么用matlab计算1000的阶乘啊?
  16. atx20pin电源短接_ATX电源20针及24针接口定义
  17. html扑克牌展开,HTML5 canvas扑克牌花式洗牌动画
  18. 如何让虚拟机mac支持独显_Mac上虚拟机的性能如何提升
  19. SpringBoot入门,快速搭建简单Web应用环境
  20. 80 after generation to marry or not to marry is a question

热门文章

  1. DB2 SQLCODE=-1585的问题解决
  2. 谈点技术吧,6万人在线每秒实时更新的解决方案
  3. 她不理我了,怎么办?
  4. 云服务器网站不能够上传视频,网站的视频要存到云服务器上吗
  5. 基于物化视图优化_CVPR2017|基于构造多视图子空间中的潜在表示解决聚类问题
  6. 编译高性能linux so库,关于如何在linux环境下生成a库和so库(改,附图)-Go语言中文社区...
  7. rpm安装两个mysql_MySQL通过rpm安装及其单机多实例部署
  8. c vs java_c++ vs java---之一
  9. 为了OFFER | 腾讯2020校招后端《解压字符串》
  10. 十一、深入Java的判断语句