1. 程式人生 > >大量刪除MySQL中的數據

大量刪除MySQL中的數據

大量 clas pre 之前 都在 引擎 公司 edi xid

出現的背景:

公司做了一個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 where
id < 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中的數據