官方建议不要经常(每小时或每天)进行碎片整理,一般根据实际情况,只需要每周或每月整理一次即可:

目录

一、MySQL 表碎片化(Table Fragmentation) 的原因

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

1、使用 show table status from db_name like 'tb_name' \G

2、查询 information_schema.TABLES 获取表的碎片化信息

三、MySQL 中如何减低表的碎片

1、OPTIMIZE TABLE XXXX

2、ALTER TABLE XXXX ENGINE = INNODB

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

问题 02:ALTER TABLE xxxx ENGINE= INNODB 索引碎片会整理么❓

3、其它工具

四、实际生产环境的应用

1、对于空表

2、对于大表


一、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),频繁的页分裂,页会变得稀疏,并且被不规则的填充,所以数据最终会有碎片。

First at all you must understand that Mysql tables get fragmented when a row is updated, so it's a normal situation. When a table is created, lets say imported using a dump with data, all rows are stored with no fragmentation in many fixed size pages. When you update a variable length row, the page containing this row is divided in two or more pages to store the changes, and these new two (or more) pages contains blank spaces filling the unused space.

表的数据存储也可能碎片化。然而数据存储的碎片化比索引更加复杂。有三种类型的数据碎片化(摘自《高性能 MySQL》):

① 行碎片(Row fragmentation)

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

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

剩余空间碎片是指数据页中有大量的空余空间。这会导致服务器读取大量不需要的数据。从而造成浪费。

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

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

关于 MySQL 中的碎片化,一般有两种方法找出碎片:

1、使用 show table status from db_name like 'tb_name' \G

单个表的碎片化情况查询。如果没有 DML 操作,Data_free 的大小为 0(单位 KB)。

2、查询 information_schema.TABLES 获取表的碎片化信息

mysql> 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 * 1024 ), 2), 'G') TABLE_DATA_SIZE, CONCAT(ROUND(index_length / ( 1024 * 1024 * 1024 ), 2), 'G') TABLE_IDX_SIZE, CONCAT(ROUND(( data_length + index_length ) / ( 1024 * 1024 * 1024 ), 2), 'G') 'TOTAL SIZE', ROUND(index_length / data_length, 2)  TABLE_IDX_FRAC, CONCAT(ROUND(( data_free / 1024 / 1024 / 1024),2), 'G') AS TABLE_DATA_FREE
FROM information_schema.TABLES
WHERE table_name='message_test_wufei';
+---------------------------+--------------+------------+------------+-----------------+----------------+------------+----------------+-----------------+
| TABLE_NAME                | TABLE_ENGINE | TABLE_TYPE | TABLE_ROWS | TABLE_DATA_SIZE | TABLE_IDX_SIZE | TOTAL SIZE | TABLE_IDX_FRAC | TABLE_DATA_FREE |
+---------------------------+--------------+------------+------------+-----------------+----------------+------------+----------------+-----------------+
| testdb.message_test_wufei | InnoDB       | BASE TABLE |   36302847 | 30.62G          | 6.30G          | 36.92G     |           0.21 | 1.05G           |
+---------------------------+--------------+------------+------------+-----------------+----------------+------------+----------------+-----------------+

三、MySQL 中如何减低表的碎片

在 MySQL 中可以使用 OPTIMIZE TABLE XXXX、ALTER TABLE XXXX ENGINE = INNODB 这两种方法降低碎片:

1、OPTIMIZE TABLE XXXX

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

OPTIMIZE TABLE XXXX 的支持表类型:InnoDB、MyISAM、ARCHIVE、NDB;OPTIMIZE操作会暂时锁表,而且数据量越大,耗费的时间就越长。

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

  • 如果表有已删除的行或拆分行(split rows),修复该表
  • 如果未对索引页面进行排序,对它们进行排序
  • 如果表的统计信息不是最新的(并且无法通过对索引进行排序来完成修复),更新它们

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

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                                                                |+----------+----------+----------+-------------------------------------------------------------------+

提示该表不支持 optimize,但是下边有显示 OK,其实已经执行成功了,5.6.X+ 的版本,其实已经支持Innodb了。

详情可进一步参考官网:https://dev.mysql.com/doc/refman/5.7/en/optimize-table.html

2、ALTER TABLE XXXX 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.

问题 01:那么是用 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 基本上是一样的。

个人建议:

① MyISAM表
mysql> optimize table 表名;
② InnoDB表
mysql> alter table 表名 engine=InnoDB;

Engine 不同,OPTIMIZE 的操作也不一样的,MyISAM 因为索引和数据是分开的,所以 OPTIMIZE 可以整理数据文件,并重排索引。InnoDB 因为聚簇索引的叶子节点包含行中所有字段的值,ALTER TABLE xxxx ENGINE= INNODB 更适合。

问题 02:ALTER TABLE xxxx ENGINE= INNODB 索引碎片会整理么❓

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

3、其它工具

使用 pt 工具或者 gh-ost 降低表的碎片化,后续测试整理,估计也是封装了上面两个命令。

四、实际生产环境的应用

1、对于空表

空表可以在主库执行 ALTER TABLE xxxx ENGINE= INNODB 进行整理,清理整个集群中该空表碎片。

2、对于大表

如果对于一张大表,直接在主库执行 ALTER TABLE xxxx ENGINE= INNODB ,会造成严重的主从同步延迟(清除碎片操作会暂时锁表,数据量越大,耗费的时间越长),影响线上业务流量。

这时,需要不记录 binlog的前提下在主从各节点分别去执行 ALTER TABLE xxxx ENGINE= INNODB 命令。

① 在执行清理碎片命令之前禁止记录 binlog
mysql> show variables like 'sql_log_bin';
mysql> SET sql_log_bin = OFF;
② 清理碎片
mysql> ALTER TABLE xxxx ENGINE = INNODB;
③ 解除 binlog 禁止
mysql> SET sql_log_bin = ON;
mysql> show variables like 'sql_log_bin';

小谈 MySQL 第十一话·InnoDB 碎片整理相关推荐

  1. MySQL中Myisam、InnoDB碎片优化

    起因:查看线上数据库中Table Information时发现有一个日志表数据大小和索引大小有915M,但实际行数只有92行.该表需要频繁插入并且会定时去删掉旧的记录.表类型为Myisam,已建立一个 ...

  2. 【MySQL】OPTIMIZE TABLE 的碎片整理功能

    1.概述 OPTIMIZE TABLE 的碎片整理功能. (1)创建测试表 t,字段 id 和 context 的类型分别为 varchar(100)和 text: mysql> create ...

  3. 小知识-为什么Linux不需要磁盘碎片整理

    ref: https://itcat.cn/post-495.html Linux不需要磁盘碎片整理的真正原因是因为Linux只是一个内核它没有磁盘可以整理. BTW,ext4已经开始提供碎片整理工具 ...

  4. 浅谈MySQL存储引擎选择 InnoDB还是MyISAM

    如果是一些小型的应用或项目,那么MyISAM 也许会更适合.当然,在大型的环境下使用MyISAM 也会有很大成功的时候,但却不总是这样的.如果你正在计划使用一个超大数据量的项目,那么你应该直接使用In ...

  5. Linux碎片整理工具,Linux不需要磁盘碎片整理

    今天老师上课时谈到过Windows的磁盘碎片整理.以前就知道Linux一般不需要进行磁盘碎片整理.但是考虑到我还有3个NTFS分区,看可不可以在Linux下对其进行整理.于是便去google--结果发 ...

  6. MySQL的存储引擎InnoDB选择了B+ 树

    我们知道数据的存储和检索是两个很重要的功能,当我们的数据量大了,怎么能快速的检索数据呢,答案是使用索引,可索引具体的技术实现有很多,选择哪一种呢,我就以mysql为例记录下它为什么选择了B+树作为索引 ...

  7. 浅谈MySQL表类型

    小小子的文章写的不错哦. 转载:http://www.xiaoxiaozi.com/2009/07/14/1171/ 浅谈MySQL表类型 MySQL为我们提供了很多表类型供选择,有MyISAM.IS ...

  8. 支付宝的数据库是MySQL变种_浅谈MySql的储存引擎(表类型)

    浅谈mysql的存储引擎(表类型) 什么是MySql数据库 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库, ...

  9. pymysq向mysql写数据 为什么本地无法查看_从运维角度浅谈MySQL数据库优化,中小企业DBA必会...

    原文:http://www.enmotech.com/web/detail/1/712/1.html(复制链接,打开浏览器即可查看原文) 作者:搬砖游击队 一个成熟的数据库架构并不是一开始设计就具备高 ...

最新文章

  1. 不降低scipy版本解决AttributeError: module ‘scipy.misc‘ has no attribute ‘imresize‘问题
  2. job kettle 导出_kettle从hive2导出数据正常,但是用kettle manager启动就报错
  3. Arcface demo
  4. xshell安装mysql步骤_mysql主从复制
  5. 去哪儿-04-iconsDev
  6. 北京联通光猫 F427 路由改桥接的方法
  7. html中怎么不让网页缩放_网页中的形状图形都是怎么画出来的?
  8. Python进阶(十二)常用数据处理模块
  9. BeautifulSoap库入门
  10. Expression Blend 中的Sketchflow for Windows Phone 7
  11. linux给文件备份,Linux文件备份
  12. 移动通信核心网技术总结(一)语音与上网业务的实现
  13. 推特开发者账号 获取推文的视频链接
  14. 线性单节锂电充电IC
  15. Win11系统默认英文字体怎么修改成为中文
  16. IDEA--工欲善其事必先利其器
  17. 关于西数黑盘那些事 原来这样滴 小伙伴们都惊呆了
  18. access violation at address 异常
  19. Log4j2漏洞复现(CVE-2021-44228)
  20. Android7.1.1系统设置默认值大全

热门文章

  1. word文档打开后无法编辑,怎么回事?
  2. Java ${}修改world内容 并转pdf,亲测可以
  3. 使用scoket发送HTTP请求
  4. beego mysql 生成_beego 代码生成工具体验
  5. linux 开发设计软件,在Linux平台下开发和设计聊天软件
  6. 抖音小店玩法具体剖析!!!
  7. Python该怎样学?大家是如何快速掌握Python的?(非常详细)
  8. spark-steaming的2种操作
  9. iOS快捷指令最全整理(支持iOS14),抖音去水印捷径快手去水印捷径
  10. STM32与PN532构建NFC近场通信指南(一):NFC及相关知识准备