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已经帮我们解决掉了,只要场景适合即可
- 对于索引更新:自然是减少频率了
参考资料
如何解决掉数据空洞问题?
下集见分晓
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了