MySQL磁盘碎片整理实例演示


Posted in MySQL onApril 03, 2022

数据库引擎以InnoDB为主

1.磁盘碎片是什么

​InnoDB表的数据存储在页中,每个页可以存放多条记录,这些记录以树形结构组织,这棵树称为B+树。

MySQL磁盘碎片整理实例演示

​聚簇索引的叶子结点包含行中所有字段的值,辅助索引的叶子结点包含索引列和主键列。

​在InnoDB中,删除一些行,这些行只是被标记已删除,而不会立即删除,个人认为和电脑的清除磁盘相同,之后可以通过覆盖旧数据实现删除,InnDB的Purge线程会异步的清理这些没用的索引键和行。但是依然不会把这些释放出来的空间还给操作系统重新使用,因此会导致页面中存在很多空洞,如果表结构中包含动态长度字段,这些空间甚至无法被InnoDB重新用来存储新的行。

​另外严重的问题是删除数据会导致页page中出现空白空间,大量随机的Delete操作必然会在数据文件中造成不连续的空白空间,当插入数据时,这些空白空间则会被利用起来,造成了数据的物理存储顺序和逻辑的排序顺序不同,这就是数据碎片。

-- 查看全局变量Purge
show variables like 'innodb_purge_threads';

解释磁盘碎片的英文博客:https://lefred.be/content/overview-of-fragmented-mysql-innodb-tables/

上面这是个大能的博客,写的pretty good!

2.实验

我们首先创建一个具有一百条数据的表来进行实验:

delimiter //
create procedure insertt()
begin
	declare i int DEFAULT 0;
	while i<1000000 do
		insert into temp values(null,'a',1);
		set i:=i+1;
	end while;
end;
//
delimiter ;
drop PROCEDURE insertt;
-- 尝试插入一百万条数据
 
call insertt()
 
-- mysql版本5.7.36
> OK
> 时间: 838.706s

创建后的磁盘存储大小:

MySQL磁盘碎片整理实例演示

​DB:information_scheme中存放我们表的信息,通过下列命令来查看我们的磁盘碎片最大的前五名

-- 别人的博客中copy的,我的猪脑写不出来
SELECT CONCAT(table_schema, '.', table_name) as 'TABLE', 
       ENGINE, CONCAT(ROUND(table_rows / 1000000, 2), 'M')  ROWS, 
       CONCAT(ROUND(data_length / ( 1024 * 1024 * 1024 ), 2), 'G') DATA, 
       CONCAT(ROUND(index_length / ( 1024 * 1024 * 1024 ), 2), 'G') IDX, 
       CONCAT(ROUND(( data_length + index_length ) / ( 1024 * 1024 * 1024 ), 2), 'G') 'TOTAL SIZE', 
       ROUND(index_length / data_length, 2)  IDXFRAC, CONCAT(ROUND(( data_free / 1024 / 1024),2), 'MB') AS data_free 
FROM information_schema.TABLES  
ORDER BY data_length + index_length desc LIMIT 5;

result:

MySQL磁盘碎片整理实例演示

我们可以看到data_free,我们最高的free空间只有6MB

innodb_ruby工具可以直接在linux系统下运行查看.Ibd文件的结构,将B+tree以及磁盘使用暴露出来,但是我不会用,这里带上他的github链接: https://github.com/akopytov/sysbench

下面我们执行删除操作:

-- 删除前五十万条数据
delete from temp order by id LIMIT 500000

文件大小:

MySQL磁盘碎片整理实例演示

删除后,磁盘文件的大小并没有变化,因为删除产生了磁盘碎片,空白page残留在文件中,被删除的数据记录仍然被保持在MySQL的链接清单中,因此数据存储文件的大小并不会随着数据的删除而减小,我们再次使用上述操作查看data_free。

MySQL磁盘碎片整理实例演示

可以看到temp表的data_free增长了。

3.对于碎片回收操作

对MySQL进行碎片整理有两种方法:

OPTIMIZE TABLE

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE table_name1 [, table_name2] ...

ALTER

ALTER TABLE table_name ENGINE = Innodb

OPTIMIZE可以同时对多个表格进行碎片整理,OPTIMIZE语句有两个可选的关键字:LOCAL和NO_WRITE_TO_BINLOG,默认是每次碎片整理都会被记录到BINlog二进制日志中去,如果带了关键字,就不会被记录到日志中去。

ALTER看起来是执行了一次空操作,重新设置了一遍数据库引擎,同时会进行碎片整理。

两种操作在一定程度是等价的。

使用optimize结果

MySQL磁盘碎片整理实例演示

磁盘文件小了一半左右

MySQL磁盘碎片整理实例演示

alter不再演示

4.后记

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

2.OPTIMIZE TABLE只对MyISAM,BDB和InnoDB表起作用,尤其是MyISAM表的作用最为明显。此外,并不是所有表都需要进行碎片整理,一般只需要对包含上述可变长度的文本数据类型的表进行整理即可。

3.在OPTIMIZE TABLE运行过程中,MySQL会锁定表。

4.默认情况下,直接对InnoDB引擎的数据表使用OPTIMIZE TABLE,可能会显示「 Table does not support optimize, doing recreate + analyze instead」的提示信息。这个时候,我们可以用mysqld --skip-new或者mysqld --safe-mode命令来重启MySQL,以便于让其他引擎支持OPTIMIZE TABLE。

补充:如何优化磁盘空间

1.优化前必看注意事项

①.优化表空间时,会造成锁表

数据量越大的表,优化耗时越长,百万条数据大约耗时30s(约25000-30000行/秒,此数据根据机器磁盘性能会有差异)。所以,在磁盘优化时,所有的增删操作将受限,请选择一个业务空档期执行。

②.间隔多久需要优化一次磁盘碎片?

Mysql官方不建议频繁进行碎片整理,比如每天都整理磁盘。可观测一次优化后,能撑多久才会产生比较大的碎片文件,然后根据这个周期,定制一个定期优化碎片的任务。

如:每周或每月凌晨3点定时清理碎片。

2.如何优化磁盘空间

判断你的数据表的引擎是什么

①.如果引擎是MyISAM,则可以通过下面SQL优化。

-- 优化表空间
optimize table tableName;

注:如果引擎是InnoDB,执行此SQL会提示:Table does not support optimize, doing recreate + analyze instead②.如果引擎是InnoDB,通过下列SQL可以代替optimize table xxx

-- 将表改为InnoDB数据库引擎
ALTER TABLE tableName ENGINE=InnoDB;

-- 分析表,查看表状态
ANALYZE TABLE tableName;

即通过重新将数据库引擎设置为InnoDB的方式,来优化磁盘空间。

到此这篇关于MySQL磁盘碎片整理的文章就介绍到这了,更多相关MySQL碎片整理内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

MySQL 相关文章推荐
MySQL创建索引需要了解的
Apr 08 MySQL
教你用eclipse连接mysql数据库
Apr 22 MySQL
解读MySQL的客户端和服务端协议
May 10 MySQL
IDEA 链接Mysql数据库并执行查询操作的完整代码
May 20 MySQL
MySQL中distinct与group by之间的性能进行比较
May 26 MySQL
MySQL 亿级数据导入导出及迁移笔记
Jun 18 MySQL
新手入门Mysql--概念
Jun 18 MySQL
mysql的数据压缩性能对比详情
Nov 07 MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
Apr 10 MySQL
详解Mysql事务并发(脏读、不可重复读、幻读)
Apr 29 MySQL
MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法
Jun 14 MySQL
MySQL count(*)统计总数问题汇总
Sep 23 MySQL
Mysql使用全文索引(FullText index)的实例代码
Apr 03 #MySQL
一文简单了解MySQL前缀索引
为什么MySQL不建议使用SELECT *
详解MySQL的主键查询为什么这么快
MySQL表锁、行锁、排它锁及共享锁的使用详解
navicat 连接Ubuntu虚拟机的mysql的操作方法
MySQL中IO问题的深入分析与优化
You might like
PHP中怎样保持SESSION不过期 原理及方案介绍
2013/08/08 PHP
初识PHP
2014/09/28 PHP
PHP使用ODBC连接数据库的方法
2015/07/18 PHP
Laravel中使用FormRequest进行表单验证方法及问题汇总
2016/06/19 PHP
Laravel构建即时应用的一种实现方法详解
2017/08/31 PHP
Extjs在exlipse中设置自动提示的方法
2010/04/07 Javascript
向当前style sheet中插入一个新的style实现方法
2013/04/01 Javascript
扩展JS Date对象时间格式化功能的小例子
2013/12/02 Javascript
Jquery 切换不同图片示例代码
2013/12/05 Javascript
javascript中checkbox使用方法实例演示
2015/11/19 Javascript
js跨域资源共享 基础篇
2016/07/02 Javascript
JavaScript 节流函数 Throttle 详解
2016/07/04 Javascript
js变量提升深入理解
2016/09/16 Javascript
nodejs个人博客开发第四步 数据模型
2017/04/12 NodeJs
node.js连接MongoDB数据库的2种方法教程
2017/05/17 Javascript
jQuery动态添加元素无法触发绑定事件的解决方法分析
2018/01/02 jQuery
javascript中的replace函数(带注释demo)
2018/01/07 Javascript
JS实现字符串去重及数组去重的方法示例
2018/04/21 Javascript
vue form 表单提交后刷新页面的方法
2018/09/04 Javascript
js回文数的4种判断方法示例
2019/06/04 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
2019/11/20 Javascript
如何搭建一个完整的Vue3.0+ts的项目步骤
2020/10/18 Javascript
利用Python+Java调用Shell脚本时的死锁陷阱详解
2018/01/24 Python
pandas 条件搜索返回列表的方法
2018/10/30 Python
pyqt5之将textBrowser的内容写入txt文档的方法
2019/06/21 Python
Python3 执行Linux Bash命令的方法
2019/07/12 Python
Python closure闭包解释及其注意点详解
2019/08/28 Python
简单了解python中的f.b.u.r函数
2019/11/02 Python
python 中的paramiko模块简介及安装过程
2020/02/29 Python
python实现快速文件格式批量转换的方法
2020/10/16 Python
java字符串格式化输出实例讲解
2021/01/06 Python
意大利网上购书网站:Libraccio.it
2021/02/03 全球购物
社团文化节邀请函
2014/01/10 职场文书
买卖车协议书
2014/04/21 职场文书
运动会稿件100字
2014/09/24 职场文书
python 实现定时任务的四种方式
2021/04/01 Python