摘要:最近由於福建開機廣告生產環境的廣告日誌備份表主鍵(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億級表資料被清空了,同時表結構也沒有被破壞!
.png)
我的相關文章參考:不停機不停服務,MYSQL可以這樣修改億級資料表結構