Insert into select引起死鎖問題分析


正常使用Insert into select去遷移數據:

INSERT INTO order_record SELECT  
    *   
FROM  
    order_today   
WHERE  
    pay_success_time < '2020-03-08 00:00:00'; 

因為是在生產環境直接備份數據,所以有加上“pay_success_time < '2020-03-08 00:00:00'”這個條件(因為歷史數據是不會再改動的),這條sql看似沒有任何問題,但是卻導致線上很多數據出現添加,修改失敗。這到底是什么原因導致的。我們先來了解下Insert into select的工作原理,在默認的事務隔離級別下:insert into order_record select * from order_today 加鎖規則是:order_record表鎖,order_today逐步鎖(掃描一個鎖一個)。從這里我們可以看出,在執行備份的時候,會導致order_today表被逐步鎖定,知道備份到最后全表鎖定。由於鎖定的數據越來越多,就導致出現了大量數據插入失敗。最后全部鎖住,導致無法插入數據。

那我們要如何避免這類問題的發生呢?

由於查詢條件會導致order_today全表掃描,什么能避免全表掃描呢,很簡單嘛,給pay_success_time字段添加一個idx_pay_suc_time索引就可以了,由於走索引查詢,就不會出現掃描全表的情況而鎖表了,只會鎖定符合條件的記錄。當然這也必須保證在歷史數據不會被更改的情況下。

修改后的sql:

INSERT INTO order_record SELECT  
    *   
FROM  
    order_today FORCE INDEX (idx_pay_suc_time)  
WHERE  
    pay_success_time <= '2020-03-08 00:00:00';  

最后總結:

使用insert into tablA select * from tableB語句時,一定要確保tableB后面的whereorder或者其他條件,都需要有對應的索引,來避免出現tableB全部記錄被鎖定的情況。

 

參考:

參考文章:

https://blog.csdn.net/asdfsadfasdfsa/article/details/83030011


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM