MYSQL数据空洞解析
## 背景引入
MYSQL中数据表A,在删除了一半的数据后,发现表空间的大小并没有减少,这是什么原因导致的呢?
定义
当对一定量数据执行delete操作时,MySQL将数据删除后进而导致页合并或者页删除,生成空闲空间,并未将空闲空间返还给操作系统,而是将当前空间标记为"可复用",当有新的数据插入时,则不会重新申请空间,而是插入到"可复用"空间中,这种"可复用"空间,称之为数据空洞。
复现背景
前提
- 使用innodb
- MYSQL版本>=5.6
解释:从 MySQL 5.6 开始,InnoDB默认采用独立表空间
我使用的版本是:

步骤
获取MYSQL存放目录(连接MYSQL后使用)
SHOW VARIABLES LIKE 'datadir';
结果例如:

拼接目录找出文件
例如dora库中的emp表即为D:\MySQL\datas\Data\dora\emp.ibt
未删除所有数据前的情况
文件大小

记录数

删除所有记录后的情况
文件大小

记录数

底层原理(delete执行的逻辑)
没有提server层的过多逻辑
- 确定要删除的记录或数据页
- 当执行
DELETE语句时,MySQL 会根据WHERE条件确定需要删除的具体记录。 - 如果没有索引支持,可能会进行全表扫描,效率较低。
- 如果有合适的索引,MySQL 会通过索引快速定位到需要删除的记录。
- 当执行
- 删除数据和相关索引
- 删除操作不仅仅是删除数据行,还需要更新与这些数据相关的索引。
- 索引中的对应条目会被删除,以保持索引的准确性和一致性。
- 触发页合并
- 当删除操作导致数据页或索引页的空间利用率低于一定阈值时,InnoDB 会触发页合并操作。
- 页合并会将相邻的空闲页合并成更大的连续空闲页,减少碎片化,提高存储效率。
- 页合并通常在后台线程中进行,以尽量减少对当前事务的影响。
- 标记释放的空间为可复用
- 删除后释放的空闲空间不会立即返还给操作系统,而是标记为可复用。
- 这些空闲空间会被优先用于后续的插入操作,减少磁盘 I/O,提高性能。
原因
原因正是删除后释放的空闲空间不会立即返回给操作系统
数据空洞的好坏
首先必须说明,需要辩证看待问题,这么设计是存在好处的:
- 减少了跟操作系统申请空间的次数(小幅度提高性能)
- 也减少了归还空间给操作系统(加快了像delete或者update的执行速度)
归根到底减少了磁盘IO
坏处则是:
磁盘空间浪费:
- 在软件与软件之间,由于MYSQL数据空洞会占用一定的磁盘空间,会导致其他软件出现空间不足等等问题
- (最最重要),在MYSQL内部也会出现问题:innoDB在MYSQL5.6后是独立表,数据空洞会导致占用掉一定的磁盘空间,而由于是独立表空间,这部分空间只能我们自己这张表使用,其他表无法利用也就会出现问题啦
查询性能下降:
- 数据空洞会影响查询性能,特别是在使用索引时。因为:
- 空洞使得数据页分布不连续,查询时磁盘 I/O 操作会更耗时(空洞导致IO更偏向随机IO了,IO成本相比于顺序IO来说耗时更长)来加载相关页。
如何规避掉数据空洞问题?
我们的思路是先分析数据空洞产生的方式,再进一步尝试降低对应的频率:
数据空洞产生的方式:
- 删除操作
- 更新索引字段
- 更新索引字段时,实际上会执行删除旧值和插入新值的操作,容易产生数据空洞。对于需要频繁更新的字段,尽量避免为其创建索引。
如何规避
- 对于删除操作:其实大多数数据库表设计的逻辑删除is_del已经帮我们解决掉了,只要场景适合即可
- 对于索引更新:自然是减少频率了
参考资料
如何解决掉数据空洞问题?
下集见分晓
MYSQL数据空洞解析的更多相关文章
- (转)mysql数据文件解析
一 数据文件 在 MySQL中每一个数据库都会在定义好(或者默认)的数据目录下存在一个以数据库名字命名的文件夹,用来存放该数据库中各种表数据文件.不同的 MySQL存储引擎有各自不同的数据文件,存放位 ...
- android开发中 解决服务器端解析MySql数据时中文显示乱码的情况
首先,还是确认自己MySql账户和密码 1.示例 账户:root 密码:123456 有三个字段 分别是_id .username(插入有中文数据).password 1)首先我们知道 ...
- MySQL数据导出导入【转】
MySQL基础 关于MySQL数据导出导入的文章,目的有二: 1.备忘 2.供开发人员测试 工具 mysqlmysqldump 应用举例 导出 导出全库备份到本地的目录 mysqldump -u$US ...
- Mysql binlog日志解析
1. 摘要: Mysql日志抽取与解析正如名字所将的那样,分抽取和解析两个部分.这里Mysql日志主要是指binlog日志.二进制日志由配置文件的log-bin选项负责启用,Mysql服务器将在数据根 ...
- mysql数据表增删改查
http://www.runoob.com/mysql/mysql-tutorial.html 一.MySQL 创建数据表 创建MySQL数据表需要以下信息: 表名 表字段名 定义每个表字段 语法 以 ...
- Mysql数据实时同步
企业运维的数据库最常见的是 mysql;但是 mysql 有个缺陷:当数据量达到千万条的时候,mysql 的相关操作会变的非常迟缓; 如果这个时候有需求需要实时展示数据;对于 mysql 来说是一种灾 ...
- Mysql索引使用解析
摘自:http://blog.chinaunix.net/uid-25063573-id-3032578.html Mysql索引使用解析 1.索引作用 在索引列上,除了上面提到的有序查找之外,数据库 ...
- MySQL 数据表操作
MySQL 数据表操作 创建MySQL数据表需要以下信息: -表名: -表字段名: -定义每个表字段: 一.创建数据表 1)mysql> create table table_name (c ...
- logstash使用template提前设置好maping同步mysql数据到Elasticsearch5.5.2
上篇blog说到采用logstash-input-jdbc将mysql数据同步到ES(http://www.cnblogs.com/jstarseven/p/7704893.html),但是这里有一个 ...
- MySQL binlog格式解析
MySQL binlog格式解析 binlog想必大家都不陌生,在主从复制或者某些情况下的数据恢复会用到.由于binlog是二进制数据,要查看一般都借助mysqlbinlog工具.这篇笔记分析了b ...
随机推荐
- ZSTU2023校赛
篠塚真佑実的树 给定\(n\)个节点的树,其中\(m\)个节点存在传送门,当飞船经过存在传送门的节点的时候,可以选择无消耗地传送至其他存在传送门的节点,现在有\(q\)次询问,每次询问给出起点\(st ...
- 解析JDBC使用查询MySQL【非流式、流式、游标】
解析JDBC使用游标查询MySQL 使用jdbc查询MySQL数据库,如果使用游标或者流式查询的话,则可以有效解决OOM的问题,否则MySQL驱动就会把数据集全部查询出来加载到内存里面,这样在大数据的 ...
- VTK 9.2 Qt 5.14 安装及错误处理
参考VTK9.1.0在Windows10+VS2019+Qt 5.15.2环境下编译安装以及VTK应用于QT_vtk-qt安装包_isongxw的博客-CSDN博客 安装注意:编译release和de ...
- R机器学习:朴素贝叶斯算法的理解与实操
最近又看了很多贝叶斯算法的一些文章,好多的文章对这个算法解释起来会放一大堆公式,对代数不好的人来说真的很头疼.本文尝试着用大白话写写这个算法,再做个例子,帮助大家理解和运用. Naive Bayes ...
- VB 的一些歧义(不断更新)
foo . bar 它可能是 foo.bar() 也可能是 foo(withObj.bar). f (a) , b 它可能是 call f(a)._DEFAULT(a)(Missing, b) 也可能 ...
- [Java]多个参数的非空判断,不要再使用多个if挨个判断了!(多参数非空判断技巧)
先上示例代码: if (StringUtils.isAnyBlank(form, to, subject, content)) { log.error("发送人,接收人,主题,内容均不可为空 ...
- pycharm选择conda虚拟环境出错:python的SDK无效
检查项如下: 0.安装了python,并在系统环境变量中配置了python 0.5 正确配置了conda的系统环境变量 1.安装conda的文件夹又读写权限(不需要管理员模式运行也能进行读写) 直接在 ...
- Spring Security OAuth2 - 自定义 OAuth2.0 令牌发放接口地址
登录实现拿浏览器网页登录举例: 基于 OAuth2.0-密码模式 实现网页登录的本质就是浏览器通过 /oauth/token 接口将 用户名 和 密码 等信息传给后台, 然后后台验证通过后返回一个有效 ...
- fabric2.0开发 部署fabric环境和fabric-samples的启动(2)
通过上一篇文章我们已经将fabric的基本环境搭建成功,接下来我们开始运行使用并初步认识fabric. 创建项目目录 mkdir -p ~/go/src/github.com/hyperledger ...
- Qt/C++音视频开发58-逐帧播放/上一帧下一帧/切换播放进度/实时解码
一.前言 逐帧播放是近期增加的功能,之前也一直思考过这个功能该如何实现,对于mdk/qtav等内核组件,可以直接用该组件提供的接口实现即可,而对于ffmpeg,需要自己处理,如果有缓存的数据的话,可以 ...