您好,登錄后才能下訂單哦!
假設,你有一個表
erp
,如果你直接進行下面的命令
drop table erp
這個時候所有的mysql的相關進程都會停止,直到
drop
結束,mysql才會恢復執行。出現這個情況的原因就是因為,在
drop table
的時候,
innodb
維護了一個全局鎖,
drop
完畢鎖就釋放了。
這意味著,如果在白天,訪問量非常大的時候,如果你在不做任何處理措施的情況下,執行了刪大表的命令,整個
mysql
就掛在那了,在刪表期間,
QPS
會嚴重下滑,然后產品經理就來找你喝茶了。所以才有了漫畫中的一幕,
你可以在晚上十二點,夜深人靜的時候再刪。
當然,有的人不服,可能會說:"
你可以寫一個刪除表的存儲過程,在晚上沒啥訪問量的時候運行一次就行。"
我內心一驚,細想一下,只能說:"大家還是別抬杠了,還是聽我說一下業內通用做法。"
先說明一下,在這里有一個前提,mysql開啟了
獨立表空間,MySQL5.6.7之后默認開啟。
也就是在
my.cnf
中,有這么一條配置(這些是屬于mysql優化的知識,后期給大家介紹)
innodb_file_per_table = 1
查看表空間狀態,用下面的命令
mysql> show variables like '%per_table'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_file_per_table | OFF | +-----------------------+-------+
如果
innodb_file_per_table
的
value
值為
OFF
,代表采用的是
共享表空間。
如果
innodb_file_per_table
的
value
值為
ON
,代表采用的是
獨立表空間。
于是,大家要問我,
獨立表空間和
共享表空間的區別?
共享表空間:某一個數據庫的所有的表數據,索引文件全部放在一個文件中,默認這個共享表空間的文件路徑在data目錄下。 默認的文件名為:ibdata1(此文件,可以擴展成多個)。
注意,在這種方式下,運維超級不方便。你看,所有數據都在一個文件里,要對單表維護,十分不方便。另外,你在做
delete
操作的時候,文件內會留下很多間隙,ibdata1文件不會自動收縮。換句話說,使用
共享表空間來存儲數據,會遭遇
drop table
之后,空間無法釋放的問題。
獨立表空間:每一個表都以獨立方式來部署,每個表都有一個.frm表描述文件,還有一個.ibd文件。
.frm文件:保存了每個表的元數據,包括表結構的定義等,該文件與數據庫引擎無關。
.ibd文件:保存了每個表的數據和索引的文件。
注意,在這種方式下,每個表都有自已獨立的表空間,這樣運維起來方便,可以實現單表在不同數據庫之間的移動。另外,在執行
drop table
操作的時候,是可以自動回收表空間。在執行
delete
操作后,可以通過
alter table TableName engine=innodb
可以整理碎片,回收部分表空間。
ps:
my.cnf
中的
datadir
就是用來設置數據存儲目錄
好了,上面巴拉巴拉了一大堆,我只想說一個 事情:
在絕大部分情況下,運維一定會為mysql選擇獨立表空間的存儲方式,因為采用獨立表空間的方式,從性能優化和運維難易角度來說,實在強太多。
所以,我在一開始所提到的前提,mysql需要開啟 獨立表空間。這個假設,百分九十的情況下是成立的。如果真的遇到了,你們公司的mysql采用的是 共享表空間的情況,請你和你們家的運維談談心,問問為啥用 共享表空間。
假設,我們有
datadir = /data/mysql/
,另外,我們有有一個
database
,名為
mytest
。在數據庫
mytest
中,有一個表,名為
erp
,執行下列命令
mysql> system ls -l /data/mysql/mytest/
得到下面的輸出(我過濾了一下)
-rw-r----- 1 mysql mysql 9023 8 18 05:21 erp.frm-rw-r----- 1 mysql mysql 2356792000512 8 18 05:21 erp.ibd
frm
和
ibd
的作用,上面介紹過了。現在就是
erp.ibd
文件太大,所以刪除卡住了。
如何解決這個問題呢?
這里需要利用了linux中
硬鏈接的知識,來進行快速刪除。下面容我上《鳥哥的私房菜》中的一些內容,
軟鏈接其實大家可以類比理解為windows中的快捷方式,就不多介紹了,主要介紹一下硬鏈接。
至于這個
硬鏈接,我簡單說一下,不想貼一大堆話過來,看起來太累。
就是對于真正存儲的文件來說,有一個
然后呢有一個
文件名
指向上面的
node Index
那么,所謂的
硬鏈接,就是不止一個
文件名
指向
node Index
,有好幾個
文件名
指向
node Index
。
假設,這會又有一個
文件名
指向上面的
node Index
,即
這個時候,你做了刪除
文件名(1)
的操作,linux系統檢測到,還有一個
文件名(2)
指向
node Index
,因此并不會真正的把文件刪了,而是把
步驟(2)
的引用給刪了,這步操作非常快,畢竟只是刪除引用。于是圖就變成了這樣
接下來,你再做刪除
文件名(2)
的操作,linux系統檢測到,沒有其他
文件名
指向該
node Index
,就會刪除真正的存儲文件,這步操作,是刪真正的文件,所以比較慢。
OK,我們用的就是上面的原理。
先給
erp.ibd
建立一個硬鏈接,利用
ln
命令
mysql> system ln /data/mysql/mytest/erp.ibd /data/mysql/mytest/erp.ibd.hdlk
此時,文件目錄如下所示
-rw-r----- 1 mysql mysql 9023 8 18 05:21 erp.frm-rw-r----- 2 mysql mysql 2356792000512 8 18 05:21 erp.ibd-rw-r----- 2 mysql mysql 2356792000512 8 18 05:21 erp.ibd.hdlk
你會發現,多了一個
erp.ibd.hdlk
文件,且
erp.ibd
和
erp.ibd.hdlk
的inode均為2。
此時,你執行
drop table
操作
mysql> drop table erp;Query OK, 0 rows affected (0.99 sec)
你會發現,不到1秒就刪除了。因為,此時有兩個文件名稱(
erp.ibd
和
erp.ibd.hdlk
),同時指向一個inode.這個時候,執行刪除操作,只是把引用給刪了,所以非常快。
那么,這時的刪除,已經把table從mysql中刪除。但是磁盤空間,還沒釋放,因為還剩一個文件
erp.ibd.hdlk
。
如何正確的刪除
erp.ibd.hdlk
呢?
如果你沒啥經驗,一定會回答我,用
rm
命令來刪。這里需要說明的是,在生產環境,直接用
rm
命令來刪大文件,會造成磁盤IO開銷飆升,CPU負載過高,是會影響其他程序運行的。
那么,這種時候,就是應該用
truncate
命令來刪,
truncate
命令在
coreutils
工具集中。
詳情,大家可以去百度一下,有人對
rm
和
truncate
命令,專程測試過,
truncate
命令對磁盤
IO,CPU
負載幾乎無影響。
刪除腳本如下
TRUNCATE=/usr/local/bin/truncatefor i in `seq 2194 -10 10 `; do sleep 2 $TRUNCATE -s ${i}G /data/mysql/mytest/erp.ibd.hdlk done rm -rf /data/mysql/mytest/erp.ibd.hdlk ;
從2194G開始,每次縮減10G,停2秒,繼續,直到文件只剩10G,最后使用
rm
命令刪除剩余的部分。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。