摘要:最近由於福建開機廣告生產環境的廣告日志備份表主鍵(int類型)達到上限(21億多),不能再寫入數據,需要重新清空下該表並將主鍵重置,但由於表里有8億多記錄的數據量,使用重置命令及DDL命令執行地非常慢,所以采取刪除物理表結構文件的方式來進行快速清空表表數據!
前言
1、本文介紹是在MySQL 5.5.29版本進行的操作,其他的版本的沒有試過,有興趣的可以自己嘗試去試下!
2、本文介紹的是刪除frm和idb文件,同時不破壞原表結構的清空數據的方式!
一、數據背景及系統介紹
為更好說明問題,首先介紹下我們系統的數據流轉的過程
step1:日志入庫。API向機頂盒/EPG提供廣告接口,采集廣告請求日志,當STB訪問EPG,EPG調用廣告請求接口獲取廣告策略,並寫入到報表數據庫的【廣告請求數據原始表t_ad_req_log】中;
step2:存儲過程備份日志表數據。由於每天產生的廣告請求數據量有2000多萬,對於etl匯總時抽取有壓力,所以通過存儲過程將7天以前的數據備份到【廣告請求數據備份表t_ad_req_log_back】中,【廣告請求數據原始表t_ad_req_log】只保留7天內的數據,約8000萬~1億2千萬記錄左右;
step3:etl抽取匯總。使用etl每小時抽取【廣告請求數據原始表t_ad_req_log】的上一時段的數據,抽取,分析,匯總寫入報表數據庫的【廣告/廣告位按時段匯總表】里面;
step4:定時刪除備份日志表數據。每隔一段時間檢查下數據etl匯總后的數據是否有問題,確認無誤數據沒問題后才將【廣告請求數據備份表t_ad_req_log_back】清空,因為該表占用空間實在太大了,不清空隔一段時間就會收到磁盤空間報警短信!
本次就是有近2個月沒有清空數據,發現就有近9億條記錄(為什么這里不用select count(*) 語句來查詢?是因為執行這樣一條語句10來分鍾都沒出結果,才用的explain來查看下表中總數據記錄)
占用磁盤空間也是高得嚇人,120G
當然不僅僅是因為占用磁盤過高,更重要的原因是,該表的主鍵值達到int類型的上限值2147483646了(21億多),這使得最新的備份數據不能繼續寫入到該備份表了
所以,確認匯總表沒有數據缺失后,急需清空該備份表的數據,並重置下主鍵
二、為什么不用DDL
通過上面確認【廣告請求數據備份表t_ad_req_log_back】表數據可刪后,當務之急就是要盡快清空數據,無疑最先想到的就是使用使用ALTER重置主鍵,執行命令:
ALTER TABLE t_ad_req_log AUTO_INCREMENT= 1;
開個小會,結果36分鍾過去沒有出現結果,尷尬了,執行線程查詢命令:
show processlist;
發現一直在“ copy to tmp table”,無奈,停下來試試執行drop命令:
DROP TABLE t_ad_req_log;
喝杯咖啡,執行了40分鍾還沒刪掉,快急出翔了。
什么叫無能為力?什么叫難以啟齒的柔弱?大概就是MySQL DDL遇到9億級表結構的時候了吧!
於是不得已另選它法——刪除表文件ibd和frm方式!
三、3分鍾刪除
當然,找到該表的文件,一鍵rm -rf 刪除還是賊爽的,輕輕松松不用3分鍾。
不過因為不知道這么刪會不會有什么關聯影響,於是就先到測試服務器做了個測試,還是遇到了些問題,記錄下步驟后,到現網刪除9億級記錄數據清空數據也是用了不到3分鍾?具體操作如下:
3.1 表結構備份
先在測試數據庫創建一個與現網【廣告請求數據備份表t_ad_req_log_back】一樣的表,然后將備份表的表文件t_ad_req_log_back.frm和t_ad_req_log_back.ibd拷貝到現網/home目錄下,這一步的操作主要是為了后面解決建表時出現的“Table `t_ad_req_log_back` already exists”問題
3.2 刪掉現網表文件
切換到mysql的data目錄下,執行刪除命令:
rm -rf t_ad_req_log_back.*
再一看,磁盤空間並沒有釋放,還是276G
於是使用lsof命令查看文件信息:
lsof -n|grep deleted
發現刪除程序還存活
繼續使用kill -9 27713命令該進程,磁盤空間得到釋放
3.3 重新建表
由於表文件已經被刪掉,該表也就不存在,使用show命令查看也確實沒有發現這個表了
於是想繼續建表,發現報錯,報錯信息一直是“Table `t_ad_req_log_back` already exists”
Google了一下,才找到原因,原來是:
由於直接刪除了表的物理文件 但mysql的信息庫 information_schema 或 mysql 庫對該表的信息還存在,也就是說InnoDB格式的表索引都保存在ibdata1這個文件中,雖然物理文件被刪除,但是ibdata1中的索引沒有刪除,所以數據庫認為該表已經存在,導致創建失敗,也就說直接rm -rf 表文件破壞了表結構。
難道這個表名就無法再用了嗎?
當然可以,j記得嗎?我們最先做了個表結構備份,現在它派上用場了,將/home目錄下的兩個表文件t_ad_req_log_back.frm和t_ad_req_log_back.ibd拷貝到數據庫的data的目錄下,發現表存在了
執行desc命令發現又報錯“Table `t_ad_req_log_back` already exists”,這是怎回事呢?

改變用戶權限
chmod 660 t_ad_req_log_back.frm chown -R mysql:mysql t_ad_req_log_back.frm
然后再drop表, 刪除之后會發現該數據庫的data目錄下的物理文件夾中還存在t_ad_req_log_back.ibd文件, 刪除該文件,然后再次建表就ok了
至此,9億級表數據被清空了,同時表結構也沒有被破壞!

我的相關文章參考:不停機不停服務,MYSQL可以這樣修改億級數據表結構