这里是一个小漫画。好的,现在就这些。假设你有一个表erp,如果直接执行如下命令:droptableerp,此时所有mysql相关的进程都会停止,直到drop结束后mysql才会恢复执行。出现这种情况的原因是,在drop表的时候,InnoDB维护了一个全局锁,drop完成后释放锁。这意味着如果在流量很大的白天不采取任何措施就执行删除大表的命令,整个mysql就会挂在那里。删表期间,QPS会严重下降,然后产品经理会来找你喝茶。所以漫画里有一个场景,你可以在晚上十二点,夜深人静的时候删掉。当然,也有人不服,可能会说:“你可以写一个删除表的存储过程,晚上没流量的时候跑一次”。别开玩笑,我跟你说说业内的通行做法。”先说明一个假设,这里有一个前提,mysql开启了独立表空间,MySQL5.6.7之后默认开启。也就是在my.cnf中,有这么一个配置(这些属于mysql优化的知识,后面会介绍给大家)。innodb_file_per_table=1查看表空间状态,使用如下命令mysql>showvariableslike'%per_table';+------------------------+-------+|Variable_name|Value|+------------------------+------+|innodb_file_per_table|OFF|+-----------------------+------+如果innodb_file_per_table的值为OFF,则表示使用共享表空间。如果innodb_file_per_table的值为ON,则表示使用了独立的表空间。那么,大家要问我了,独立表空间和共享表空间有什么区别呢?共享表空间:将某个数据库的所有表数据和索引文件放在一个文件中。默认情况下,此共享表空间的文件路径在数据目录中。默认文件名是:ibdata1(这个文件可以扩展成几个)。注意,这种方式运维超级不方便。你看,所有的数据都在一个文件里,维护一张表很不方便。另外,在做删除操作的时候,文件会有很多空隙,ibdata1文件不会自动收缩。也就是说,使用共享表空间存储数据,会遇到droptable后空间无法释放的问题。独立表空间:每张表独立部署,每张表有一个.frm表描述文件,一个.ibd文件。.frm文件:保存了每个表的元数据,包括表结构的定义等,这个文件与数据库引擎无关。.ibd文件:保存各表的数据和索引的文件。注意,这样每张表都有自己独立的表空间,方便运维,可以实现单表在不同数据库之间的移动。另外,在执行droptable操作时,可以自动回收表空间。执行删除操作后,可以执行altertableTableNameengine=innodb语句对表空间进行碎片整理和回收。ps:my.cnf中的datadir用于设置数据存放目录。有很多废话。我只想说一点:在大多数情况下,运维肯定会为mysql选择独立表空间的存储方式,因为它使用了独立表空间,从性能优化和运维的角度来说要强很多.所以,我一开始提到的前提,mysql需要开独立的表空间。这个假设在90%的情况下都是正确的。如果你真的遇到了,你公司的mysql使用的是共享表空间,请找你家运维说说,问问你为什么要使用共享表空间。正确的姿势是假设我们有datadir=/data/mysql/,我们有一个名为mytest的数据库。在数据库mytest中,有一个名为erp的表,执行如下命令:mysql>systemls-l/data/mysql/mytest/得到如下输出(我过滤了)-rw-r-----1mysqlmysql902381805:21erp.frm-rw-r-----1mysqlmysql235679200051281805:21erp.ibdfrm和ibd的作用上面已经介绍过了。现在erp.ibd文件太大,所以删除卡住了。如何解决这个问题呢?这里就需要利用到linux中硬链接的知识来进行快速删除。下面就让我来介绍一下《鸟哥的私房菜》中的一些内容吧。其实软链接可以类比理解为windows中的快捷方式,就不多介绍了。我主要介绍一下硬链接。至于这个硬链接,我简单说一下,不想发很多字,好像太累了。即对于真正存储的文件,有一个指向存储文件的InodeIndex:那么有一个文件名指向的InodeIndex:那么,所谓硬链接就是指多个文件名指向InodeIndex,有几个文件名指向InodeIndex。假设还会有另一个文件名指向上面的InodeIndex,即:此时你删除文件名(1),Linux系统检测到还有另一个文件名(2)指向这个InodeIndex,so文件并没有真正被删除,而是删除了对文件名(1)的引用。这一步很快,毕竟只是删除引用。于是画面变成了这样:接下来,你执行删除文件名的操作(2),linux系统检测到没有其他文件名指向InodeIndex,真正的存储文件就会被删除。这个操作是删除真实文件,所以比较慢。OK,我们就是利用上面的原理。首先为erp.ibd创建硬链接,使用ln命令mysql>systemln/data/mysql/mytest/erp.ibd/data/mysql/mytest/erp.ibd.hdlk此时文件目录如下:-rw-r-----1mysqlmysql902381805:21erp.frm-rw-r-----2mysqlmysql235679200051281805:21erp.ibd-rw-r-----2mysqlmysql235679200051281805:21erp.ibd.hdlk你会发现有再来一个erpibd.hdlk文件,erp.ibd和erp.ibd.hdlk的innode都是2,此时你执行droptable操作:mysql>droptableerp;QueryOK,0rowsaffected(0.99sec)你会发现不到1秒被删除。因为,此时,有两个文件名(erp.ibd和erp.ibd.hdlk),同时指向一个innode。此时删除操作只是删除引用,所以很快。那么,此时的删除已经将表从mysql中删除了。但是磁盘空间并没有释放,因为还剩下一个文件erp.ibd.hdlk。如何正确删除erp.ibd.hdlk?如果你没有经验,你肯定会回答我,用rm命令删除。这里需要说明的是,在生产环境中,直接使用rm命令删除大文件会导致磁盘IO开销飙升,CPU负载过高,影响其他程序的运行。那么,这个时候就应该使用truncate命令来删除。需要注意的是,truncate命令在coreutils工具集中,需要单独安装。具体可以去百度查看安装教程。此外,网上还流传着一些文章。这些文章专门测试了rm和truncate命令。truncate命令对磁盘IO和CPU负载几乎没有影响。删除脚本如下:TRUNCATE=/usr/local/bin/truncateforiin`seq2194-1010`;dosleep2$TRUNCATE-s${i}G/data/mysql/mytest/erp.ibd.hdlkdonerm-rf/data/mysql/mytest/erp.ibd.hdlk;从2194G开始,每次减少10G,停2秒,继续,直到文件只剩下10G,最后用rm命令删除剩下的部分。其他情况这里指的是如果数据库部署在windows上怎么办。我不够专业,无法回答这个问题。因为我从出道到现在都没遇到过。生产环境,mysql是基于windows的。假设真的遇到了,windows下有一个叫mklink的工具,可以在windows下创建硬链接,应该可以完成类似的功能。总结第一篇mysql文章,试试水,这篇文章有点偏运维,中小公司的研发比较容易遇到。因为中小型公司没有专业的DBA,开发童鞋的时候要包揽一切。希望大家有所收获。
