MySQL小技巧:删除大表数据时,drop table执行不下去怎么办

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL小技巧:删除大表数据时,drop table执行不下去怎么办相关的知识,希望对你有一定的参考价值。

参考技术A 最近遇到了一个坑,mysql数据库服务器硬盘容量告警,而且因为非技术原因,还不能追加硬盘。

通过监控发现,磁盘IO一直100%。直接影响就是系统处理时间越来越长,接口响应耗时也越来越多。

经过分析,发现mysql业务数据库里有好几张大表,而且这几张大表行数都在5000万以上,文件大小都在100G和150G之间。

因为这些表都是备份表,第一反应就是找DBA直接清理掉这些表。 潜意识里以为drop table 和 truncate table效率很高,都会快速完成,但事实上不是。 但意外的是,在执行drop table时,直接导致数据库挂起了,而且还发生了主从切换。

第一次尝试失败。

第一次失败反应出来的问题是,如果数据文件过大,drop table操作也得慎用。

那我们可以在drop table之前,想办法把数据文件逻辑清空。比如Linux硬连接的方式,具体步骤如下(假如目标表名是test):

ln test.ibd test.ibd.hdlk

drop table test;

此时,磁盘上真实的数据其实没删除,但数据库里的表,已经删除了。

rm test.ibd.hdlk

到此,数据就能快速清理成功了。

MySQL DROP TABLE操作以及 DROP 大表时的注意事项

语法:

删表

DROP TABLE Syntax
DROP [TEMPORARY] TABLE [IF EXISTS]
    tbl_name [, tbl_name] ...
    [RESTRICT | CASCADE]

可一次删除一张或多张表。需具有所删除表上的DROP权限。

表定义文件和数据文件均被移除。表被删除后表上的用户权限不会被自己主动删除。

參数里表中指定的表名不存在则报错,但对于存在的表仍会删除。可通过指定IF EXISTS阻止表不存在时引发的错误(此时对于不存在的表仅产生一个NOTE)。对于分区表。除了移除表定义,分区、数据外还移除与之关联的分区定义文件(.par)。

在MySQL5.6中參数[RESTRICT | CASCADE]不做不论什么事情。

[TEMPORARY] keyword表明仅仅删暂时表,语句不会结束正在进行的事务(MySQL中DDL语句会隐式提交)。不会进行权限检查。


删库
DROP DATABASE Syntax
DROP {DATABASE | SCHEMA} [IF EXISTS] db_name...
删除指定库中的表之后删除库。需具有库上的DROP权限。

库被删除后库上存在的用户权限不会被自己主动删除。IF EXISTS用于阻止库名不存在时引起的错误。库被删除后默认库会被重置。

若在使用了符号链接的库上运行DROP DATABASSE 链接和原始数据库都会被删除。命令返回被移除的表数量。
该命令会从指定的数据库文件夹中移除常规操作时MySQL自己产生的文件和文件夹。如:.BAK .DAT .HSH .MRG. MYD .MYI .TRG .TRN .db.frm .ibd .ndb .par若存在db.opt也相同会删除。若数据库文件夹中存在其它非MySQL本身产生的文件或文件夹。则整个数据库文件夹不会被移除。此时,需手动清理剩余的文件并又一次执行DROP DATABASE语句。
删除数据库并不会移除库中创建的暂时表。暂时表在SESSION结束时自己主动被清理或者显示的通过DROP TEMPORARY TABLE 删除。

删除大表的注意事项
对于表的删除。由于InnoDB引擎会在table cache层面维护一个全局独占锁一直到DROP TABLE完毕为止。这样。对于表的其它操作会被HANG住。对于较大的表来说,DROP TABLE操作可能须要非常长的时间。因此须要一种有效的办法来提升大表的删除速度,以尽可能减少HANG住的时间。能够通过设置硬链接来达到此目的。


比方有一个例子表:
example_table

使用InnoDB引擎且指定innodb_file_per_table=ON时在数据文件夹中与该表相应的有例如以下两个文件。分别为表定义文件和数据文件。


sudo ls  -lh /data/mysql/testdb
-rw-rw---- 1 mysql mysql 8.4K Oct 28 13:26 example_table.frm
-rw-rw---- 1 mysql mysql 100G Oct 28 13:26 example_table.ibd
该表有100G这么大。直接使用DROP TABLE来完毕删表动作,那么这条语句要运行非常长时间。此时便能够通过在该表相应的数据文件上设置硬链接来进行删除。


sudo ln /data/mysql/testdb/example_table.ibd /data/mysql/testdb/example_table.ibd.hdlk
sudo ls  -lh /data/mysql/testdb
-rw-rw---- 1 mysql mysql 8.4K Oct 28 13:26 example_table.frm
-rw-rw---- 2 mysql mysql 100G Oct 28 13:26 example_table.ibd
-rw-rw---- 2 mysql mysql 100G Oct 28 13:26 example_table.ibd.hdlk
发现多了一个example_table.ibd.hdlk文件,且example_table.ibd.hdlk和example_table.ibd的innode均为2。也即当有多个文件名称(如硬链接)指向同一innode时,这个innode的引用数大于1。此时,删除当中不论什么一个文件名称都仅仅会删除指向innode的指针而并不会直接删除物理文件块。因此会很快。直至innode的引用计数等于1时才会真正删除相应的物理文件块。真正删除物理文件块时才会比較耗时。



在建立了硬链接后再运行DROP TABLE操作:

DROP TABLE example_table;
发现会非常快的完毕。查看相应的表定义和数据文件:
sudo ls  -lh /data/mysql/testdb
-rw-rw---- 1 mysql mysql 100G Oct 28 13:26 example_table.ibd.hdlk
仅仅剩下example_table.ibd.hdlk,且innode的引用计数变为了1。

也即刚才的DROP TABLE操作实施删除了物理文件的一个指针example_table.ibd ,因而很快。



剩下的任务就是删除真正的物理文件了,由于此时innode的引用计数已经变为了1。直接删除example_table.ibd.hdlk便会真正的删除物理文件。

但由于物理文件较大。删除大文件仍会引起较高的磁盘IO开销。

因此能够使用少量逐次删除的方式来删除大的数据文件。truncate工具能够用于添加或缩减指定文件的尺寸,能够用于此目的:

for i in `seq 100 -1 1 ` ;do sleep 2;sudo truncate -s ${i}G /data/mysql/testdb/example_table.ibd.hdlk;done
sudo rm -rf /data/mysql/testdb/example_table.ibd.hdlk;
从100G開始。每次缩减1G,停2秒,继续,直到文件仅仅剩1G,最后使用rm命令删除剩余的部分。



对于整个数据库的删除能够先删除当中较大的表。最后在运行DROP DATABASE删除整个库。对大表的删除可參见上面的方法。







































以上是关于MySQL小技巧:删除大表数据时,drop table执行不下去怎么办的主要内容,如果未能解决你的问题,请参考以下文章

Innodb中mysql如何快速删除2T的大表

MySQL DROP TABLE操作以及 DROP 大表时的注意事项

MySQL大表drop/truncate操作流程

MySQL大表drop/truncate操作流程

大表分批删除脚本之MySQL版

MYSQL百G大表正确清空方式