删除idb文件后磁盘空间不释放

先说结论后看具体场景

rm 删除文件后,如果文件正被进程使用,是不会被真实删除的。虽然执行了rm命令但其仍然存在于磁盘中且被进程引用。

重启进程服务后会被真正删除

truncate table

MySQL单表太大,但表数据又没什么用的时候,可以通过truncate table来实现。

delete 不释放 ibd 表空间

如果你心存疑问,为什么不使用delete from table where ​来定时删除呢?

因为在删除sql语句中,写法如下:DELETE FROM ueb_logistics_rule_logs WHERE type=0 LIMIT 100; 凡是这样,delete带有where条件的,都不是真删除,只是MySQL给记录加了个删除标识,自然这样操作后表数据占有空间也不会变小了。

具体可以复习一下 mysql 的 mvcc 多版本并发控制。

MVCC 机制的实现就是通过 read-view 机制与 undo 版本链比对机制,使得不同的事务会根据数据版本链对比规则读取 同一条数据在版本链上的不同版本数据。

delete 对于删除情况可以认为是 update 的特殊情况,会将版本链上最新的数据复制一份,然后将 trx_id 修改成删除操作的 trx_id,同时在该条记录的头信息(record header)里的标记位(delete flag)写上 true,表示当前记录已经被删除,在查询时按照上面的规则查询对应的记录,如果删除标记位为 true,意味着记录已经被删除,则不返回数据。

解决办法:

OPTIMIZE TABLE 来回收未使用的空间,并整理数据文件的碎片。

但是 OPTIMIZE TABLE只对MyISAM, BDB表起作用,。

innodb的数据库不支持optimize,可以用 ALTER TABLE tableName ENGINE='InnoDB'(前提是innodb_file_per_table = ON)

该方法会对旧表以复制的方式新建一个新表,然后删除旧表。虽然这个过程是安全的,但是在进行操作时还是先进行备份为好。
然后对表的索引信息做重新统计。尤其是当表数据量级比较大的时候,还是谨慎使用。
analyze table tableName

rm tableName.ibd 文件不释放磁盘空间

truncate方法和delete form where 方法都有人使用过了,当然这也是本能想到的方法。但我偏要剑走偏锋,于是我选择了另外一个有坑的不太好的方法,虽然如此,但因为是开发环境无所顾忌,且还学习到了东西。very good。

直接删除ibd文件,以为这样可以立即释放空间,但事与愿违,空间没有一丝一毫的释放。那么空间去哪里了呢,找了垃圾回收站,里边没有。于是开始挨个目录运行du -h --max-depth=1|sort -r -h,也没有定位到,奇怪了。

lsof命令

然后,徐东成告诉我用lsof 命令试试。

[root@test mnt]# lsof | grep delete
beam.smp      541   601 polkitd      67w      REG               0,40        1292   45630035 /var/log/rabbitmq/log/crash.log.3 (deleted)
sys\_sig\_d      541   600 polkitd      67w      REG               0,40        1292   45630035 /var/log/rabbitmq/log/crash.log.3 (deleted)
sys\_msg\_d   541   601 polkitd      67w      REG               0,40        1292   45630035 /var/log/rabbitmq/log/crash.log.3 (deleted)
async\_1         541   602 polkitd      67w      REG               0,40        1292   45630035 /var/log/rabbitmq/log/crash.log.3 (deleted)
async\_2         541   603 polkitd      67w      REG               0,40        1292   45630035 /var/log/rabbitmq/log/crash.log.3 (deleted)

[root@test mnt]# lsof | grep delete|grep sy_job_log
mysqld      884             mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap_job_yl/sy_job_log.ibd (deleted)
mysqld      884   885   mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap_job_yl/sy_job_log.ibd (deleted)
mysqld      884   886   mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap_job_yl/sy_job_log.ibd (deleted)
mysqld      884   887   mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap_job_yl/sy_job_log.ibd (deleted)
mysqld      884   888   mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap_job_yl/sy_job_log.ibd (deleted)
mysqld      884   889   mysql   64uW     REG              253,0 49782194176   17871262 /data/mysql_data/hap

这里的命令lsof | grep delete|grep sy_job_log用于查找正在使用或引用已删除文件的进程。在你提供的输出中,你正在查找与sy_job_log相关的删除的文件。

根据输出,可以看到mysqld进程(MySQL数据库服务器)正在使用名为sy_job_log.ibd的已删除文件。这通常发生在文件被删除或移动后,但仍然被某个进程打开的情况下。当文件被删除时,文件系统会将其标记为“已删除”,但如果仍然有进程在使用该文件,文件系统不会真正释放磁盘空间。

在这种情况下,你可能需要终止或重新启动相关的mysqld进程来释放对该文件的引用。你可以尝试以下步骤:

  1. 确认你具有足够的权限来停止或重新启动mysqld进程。
  2. 使用适当的命令停止mysqld进程,例如sudo service mysql stopsudo systemctl stop mysql(具体命令取决于你的操作系统和MySQL的安装方式)。
  3. 等待一段时间,确保mysqld进程完全停止。
  4. 重新启动mysqld进程,使用适当的命令,例如sudo service mysql startsudo systemctl start mysql
  5. 再次执行lsof | grep delete|grep sy_job_log命令,确认已删除文件是否不再显示在结果中。

这样做应该可以解决文件被删除但仍被进程使用的问题。请注意,在执行上述步骤之前,请务必备份重要的数据库文件以防万一。

mysql ibd文件缺失无法启动

搞完之后,重启mysql发现重启失败

[root@test hap_job_yl]# sudo service mysql restart
Redirecting to /bin/systemctl restart mysql.service
Job for mysqld.service failed because the control process exited with error code. See "systemctl status mysqld.service" and "journalctl -xe" for details.
[root@test hap_job_yl]# systemctl status mysqld.service
● mysqld.service - LSB: start and stop MySQL
   Loaded: loaded (/etc/rc.d/init.d/mysqld; bad; vendor preset: disabled)
   Active: failed (Result: exit-code) since 二 2023-08-15 19:06:42 CST; 14s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 28243 ExecStop=/etc/rc.d/init.d/mysqld stop (code=exited, status=0/SUCCESS)
  Process: 29488 ExecStart=/etc/rc.d/init.d/mysqld start (code=exited, status=1/FAILURE)

815 19:06:40 test systemd[1]: Starting LSB: start and stop MySQL...
815 19:06:42 test mysqld[29488]: Starting MySQL.. ERROR! The server quit without updating PID fi...id).
815 19:06:42 test systemd[1]: mysqld.service: control process exited, code=exited status=1
815 19:06:42 test systemd[1]: Failed to start LSB: start and stop MySQL.
815 19:06:42 test systemd[1]: Unit mysqld.service entered failed state.
815 19:06:42 test systemd[1]: mysqld.service failed.
Hint: Some lines were ellipsized, use -l to show in full.

原因是缺少ibd文件,从别的环境搞一个过来

scp sy_job_log.ibd [email protected]:/data/mysql_data/hap_job_yl/

重启还是失败,定位一下原来是复制过来的文件,mysql用户没有权限访问

赋权一下

[root@test hap_job_yl]# chown -R mysql:mysql sy_job_log.ibd 

重启okey了。

[root@test hap_job_yl]# sudo service mysql restart

你可能感兴趣的:(mysql)