【MySQL】truncate拋異常System Lock

一. 背景

表數據大概幾十萬,不到五十萬
每隔10幾分鐘使用truncate清空數據,然後再寫入等量數據
數據庫主從結構
數據庫版本5.7

二. 現象

執行truncate時從庫偶發拋異常【System Lock】,非必現。佔用線程資源,導致後續SQL語句全部阻塞
從庫不可用,進而導致路由到該從庫的請求全部阻塞,從而導致應用雪崩

三. 分析

網上搜了很多資料,都說是truncate在MySQL5.7及以下版本的bug,drop命令可以解決此問題,升級到8.0也可以解決此問題。
網上資料說數據量達到幾千萬纔會出現此問題,實際上幾十萬就出現。原因可能和相關配置、系統併發量有關
MDL寫鎖原因(猜測?)

  1. 參考資料:https://time.geekbang.org/column/article/69862
  2. 資料中說:對錶的增刪改查會加MDL讀鎖(表級鎖);對錶結構做變更會加寫鎖(表級鎖)(DDL語句),讀寫鎖/寫鎖之間互斥。
  3. truncate屬於DDL語句,即執行後會加MDL寫鎖(表級鎖),其它對錶的操作都會堵塞(包括查詢),而由於truncate的一些機制(可能是bug)導致一直無法釋放鎖(偶發現象),結果導致【System Lock】

四. 解決思路

MySQL版本:5.7
表名:tb1
思路:使用drop 替代 truncate

方案一

  1. drop tb1_temp(如果存在)
  2. 重命名tb1爲tb1_temp
  3. 創建新表tb1
  4. 寫入數據到tb1
  5. drop tb1_temp

方案二(選中)

  1. drop tb1_new,tb1_bak(如果存在就刪除)
  2. 創建表tb1_new
  3. 寫入數據到tb1_new
  4. 重命名tb1到tb1_bak
  5. 重命名tb1_new到tb1
  6. drop tb1_bak

五. 結論

最終選中方案二
兩者的區別在於

  1. 方案二的數據不一致及表不可以用的時間點在(4,5)兩步。只涉及表重命名,時間較短
  2. 方案一的數據不一致及表不可以用的時間點在(2,3,4)兩步。涉及到寫入數據,時間較長
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章