大量刪除MySQL中的數據
出現的背景:
公司做了一個redis相關的項目,其中mysql存儲了很多統計數據。比如客戶端上報的數據,redis實例的數據,應用的數據,機器的數據等。每天都在上報,采集,由於沒有定期刪除,數據大量累積。大概有一年左右的數據,一個表的數據已經達到億級別的。這樣算下來,一個表的數據至少是幾十GB了。因此需要刪除過期的數據,暫時保留近三個月的統計數據。
解決方案:
基本每個表都有個字段叫create_time或者collect_time的字段,只要刪除這個字段三個月之前的數據就ok了
delete from table_name where create_time < ‘2017-04-06‘
只要執行這句SQL應該就可以了
遇到的問題:
The total number of locks exceeds the lock table size in MySQL
因為需要刪除的數據太大,mysql給的buffer好像只有8MB左右(網上搜到的)
後面找到DBA幫忙看,問這個表建了索引沒有
show index from table_name
通過查看索引,我們在create_time和collect_time上是建了索引的,索引類型是BTree,ASC。這裏我們用的Mysql引擎是InnoDb
delete from table_name where create_time < ‘2017-07-06‘order by create_time asc limit 10000
接著,我想用order by + limit實現刪除,還是出現了上面的錯誤
後面DBA提示我說,為啥不用ID刪除,說按id刪除,速度和按索引列刪除,不是一個數量級的
接著我想到了拆分一下。
最終解決方案:
找出符合條件的create_time和collect_time的最大ID
select max(id) from table_name where create_time < ‘2017-04-06‘
這裏千萬左右的數據大概需要10多秒
接著按id刪除,一次刪除10k,循環刪除
delete from table_name whereid < maxId limit 10000
直到把過期的時間刪除完成
這裏我沒有msyql服務器的權限,通過java客戶端連接刪除,使用的spring jdbcTemplate這個接口
另外,這裏一次刪除10k還有個原因是,事務太大,影響其他服務的運行
還用到的技術,就是使用線程池來執行sql刪除,實現異步刪除。和同事吃飯的時候,同事也提供了一個解決方案,每次刪一秒的數據,這樣一次次的刪。看了一下數據,一秒的數據基本在幾十萬,左右,這樣不太好控制數據量大小。還是通過主鍵id + limit 10k這裏穩妥一點。
還有一點就是,為了怕壓到mysql服務器,這裏線程池刪除的時候回sleep(1000),阻塞1s再刪除,減輕mysql服務器的壓力
今天搞了一下數據刪除這一點東西,感覺mysql水很深,比如一個select count(*)的執行過程,select from table_name order by id limit 的過程,索引,各種連接,引擎的工作原理。走的時候還有點沒有調完,明天應該可以搞定這些了。
大量刪除MySQL中的數據