MySQL Delete 删数据后磁盘空间未释放的原因

问题描述

在 MySQL 中使用 delete 语句删除数据之后,监控视图中可用的磁盘空间没有增加,磁盘使用率没有下降等等。

解决方案

delete 不释放空间是 MySQL 自身机制的原因,需要重建表才可以释放磁盘空间,可以参考的操作:

  1. 执行 optimize table ${table_name}。
  2. 如果是 InnoDB 的表,执行 alter table ${table_name} engine = innodb。

需要注意以下两个问题:

这两个命令都会重建表,尽量不要在磁盘空间紧张(>90%)的时候进行操作,先扩容磁盘,操作完之后再缩容。
这两个命令在开始和结束的时候都会尝试获取 metadata lock,所以尽量不要在业务高峰期执行。

问题分析

在 MySQL 的机制中,delete 删除的行只是被标记为删除状态,如果删除的行很多,整个数据页(innodb_page)的行都会被删除的时候,数据页也只会标记为删除,都不会真正的物理删除,而是一直占用,等待被复用。

例如:

可以看到 delete 前后,data_length 并没有发生变化,但是 data_free 增加了很多。这说明数据虽然删了,但是并没有被释放,仍旧被 test1 表占用,只是显示处于 free 状态,以后再写入新数据的时候就可以直接复用,而不需要在申请新的磁盘空间了。

这个时候使用alter table test1 engine = innodb 看看效果:

可以看到 data_length 和 data_free 都变成了空表的状态,仅有一个 innodb_page (默认 16k)。

PS:data_free 本身也可以用来评估表的空间碎片,当这个数字非常高的时候,可以考虑用同样的方法重建表,回收一部分磁盘空间。

以上就是MySQL Delete 删数据后磁盘空间未释放的原因的详细内容,更多关于MySQL 删数据后磁盘空间未释放的资料请关注我们其它相关文章!

(0)

相关推荐

  • mysql利用mysqlbinlog命令恢复误删除数据的实现

    实验环境: MYSQL 5.7.22 开启二进志日志 日志格式MIXED 实验过程: 1.执行:FLUSH LOGS; master-bin.000014 文件就是新生成的文件 刷新日志是为了实验内容更直观,更容易观察到整个实验过程的内容. 我看到网上许多文章有在用REST MASTER;而未说明此命令的严重性 这条命令会删除所有日志文件,并将文件名和记录点进行重置归零,99%的情况下是用不到这条命令的 删除日志可以用PURGE MASTER LOGS...这样保险一点 2.新日志文件已经生成,

  • MySQL删除数据,表文件大小依然没变的原因

    对于运行很长时间的数据库来说,往往会出现表占用存储空间过大的问题,可是将许多没用的表删除之后,表文件的大小并没有改变,想解决这个问题,就需要了解 InnoDB 如何回收表空间的. 对于一张表来说,占用空间重要分为两部分,表结构和表数据.通常来说,表结构定义占用的空间很小.所以空间的问题主要和表数据有关. 在 MySQL 8.0 前,表结构存储在以 .frm 为后缀的文件里.在 8.0,允许将表结构定义在系统数据表中. 关于表数据的存放 可以将表数据存在共享表空间,或者单独的文件中,通过 inno

  • mysql5.7.33误删除ibdata文件找回数据的方法

    一.场景说明: 很多时候因为 MySQL 数据库不能启动而造成数据无法访问,但应用的数据通常没有丢失,只是系统表空间等其它文件损坏了,或者遇到 MySQL 的 bug. 这个时候如果没有备份,很多人就以为数据丢失了,但实际上大部分时候数据还是有救的. 对于 MyISAM 引擎的表空间,直接把对应的数据文件拷贝到一个新的数据库就行了,数据就可以恢复了. 对于 InnoDB 引擎的数据库表空间可以采用传输表空间的方式把数据救回来. 前提是MySQL开启了参数 innodb_file_per_tabl

  • MyBatis批量插入/修改/删除MySql数据

    前言 由于项目需要生成多条数据,并保存到数据库当中,在程序中封装了一个List集合对象,然后需要把该集合中的实体插入到数据库中,项目使用了Spring+MyBatis,所以打算使用MyBatis批量插入,应该要比循环插入的效果更好,由于之前没用过批量插入,在网上找了一些资料后最终实现了,把详细过程贴出来.供以后查阅和学习. java代码: 注意:这里循环的时候需new 出来新的对象,而不能通过循环改变属性的值就认为这是一个新的对象了,通俗的说就是new ReddemCode()要放在for循环的

  • Python批量删除mysql中千万级大量数据的脚本分享

    场景描述 线上mysql数据库里面有张表保存有每天的统计结果,每天有1千多万条,这是我们意想不到的,统计结果咋有这么多.运维找过来,磁盘占了200G,最后问了运营,可以只保留最近3天的,前面的数据,只能删了.删,怎么删? 因为这是线上数据库,里面存放有很多其它数据表,如果直接删除这张表的数据,肯定不行,可能会对其它表有影响.尝试每次只删除一天的数据,还是卡顿的厉害,没办法,写个Python脚本批量删除吧. 具体思路是: 每次只删除一天的数据: 删除一天的数据,每次删除50000条: 一天的数据删

  • 浅谈为什么MySQL不建议delete删除数据

    前言 我负责的有几个系统随着业务量的增长,存储在MySQL中的数据日益剧增,我当时就想现在的业务方不讲武德,搞偷袭,趁我没反应过来把很多表,很快,很快啊都打到了亿级别,我大意了,没有闪,这就导致跟其Join的表的SQL变得很慢,对的应用接口的response time也变长了,影响了用户体验. 事后我找到业务方,我批评了他们跟他们说要讲武德,连忙跟我道歉,这个事情才就此作罢,走的时候我对他们说下次不要这样了,耗子尾汁,好好反思. 骂归骂,事情还是得解决,时候我分析原因发现,发现有些表的数据量增长

  • Mysql删除数据以及数据表的方法实例

    在Mysql 中删除数据以及数据表非常的容易,但是需要特别小心,因为一旦删除所有数据都会消失. 删除数据 删除表内数据,使用delete关键字. 删除指定条件的数据 删除用户表内id 为1 的用户: delete from User where id = 1; 删除表内所有数据 删除表中的全部数据,表结构不变. 对于 MyISAM 会立刻释放磁盘空间,InnoDB 不会释放磁盘空间. delete from User; 释放磁盘空间 optimize table User; 删除数据表 删除数据

  • MySQL 快速删除大量数据(千万级别)的几种实践方案详解

    笔者最近工作中遇见一个性能瓶颈问题,MySQL表,每天大概新增776万条记录,存储周期为7天,超过7天的数据需要在新增记录前老化.连续运行9天以后,删除一天的数据大概需要3个半小时(环境:128G, 32核,4T硬盘),而这是不能接受的.当然如果要整个表删除,毋庸置疑用 TRUNCATE TABLE就好. 最初的方案(因为未预料到删除会如此慢),代码如下(最简单和朴素的方法): delete from table_name where cnt_date <= target_date 后经过研究,

  • mysql数据库删除重复数据只保留一条方法实例

    1.问题引入 假设一个场景,一张用户表,包含3个字段.id,identity_id,name.现在身份证号identity_id和姓名name有很多重复的数据,需要删除只保留一条有效数据. 2.模拟环境 1.登入mysql数据库,创建一个单独的测试数据库mysql_exercise create database mysql_exercise charset utf8; 2.创建用户表users create table users( id int auto_increment primary

  • mysql 大表批量删除大量数据的实现方法

    问题参考自:https://www.zhihu.com/question/440066129/answer/1685329456 ,mysql中,一张表里有3亿数据,未分表,其中一个字段是企业类型,企业类型是一般企业和个体户,个体户的数据量差不多占50%,根据条件把个体户的行都删掉.请问如何操作?答案为个人原创 假设表的引擎是 Innodb, MySQL 5.7+ 删除一条记录,首先锁住这条记录,数据原有的被废弃,记录头发生变化,主要是打上了删除标记.也就是原有的数据 deleted_flag

随机推荐