insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证
作者:網易數據庫團隊
DDB(網易杭研自研的MySQL數據庫中間件產品)團隊小伙伴發現了一個問題,覺得比較奇怪。于是找到我們,希望解釋下。過程中除解釋了問題的現象,也通過代碼了解了更多的InnoDB DML執行邏輯,還發現了MySQL/InnoDB官方在二級唯一索引沖突檢查時加鎖行為的反復。本系列打算用三四篇文章來聊聊這個事情。這是第三篇,用實際案例來證明假設。
第二篇鏈接:
MySQL RC級別下并發insert鎖超時問題 - 源碼分析
我們舉update為例,因為update可以轉化為delete+insert,所以也就包含了insert的場景。仍然采用前述的表dt和其中的9條記錄。
二級唯一索引場景
我們嘗試對id為6的記錄做2次update,并在第二次的時候gdb跟蹤detail7_1的唯一性約束檢查流程。
session1-ddb>begin; Query OK, 0 rows affected (0.00 sec)session1-ddb>update dt set id = 66 where id = 6; Query OK, 1 row affected (6 min 3.98 sec) Rows matched: 1 Changed: 1 Warnings: 0session1-ddb>update dt set id = 666 where id = 66;第一個update將主鍵id為6的記錄更新為66,按照代碼邏輯,由于修改了n_uniq字段,所以會走delete+insert,而detail7_1由于主鍵id在其n_fields中,所以也需要更新該索引,也是走delete+insert。此時detail7_1就存在2條n_uniq均為('1','6')的記錄,第一條應該是heap_no為7,第二條應該heap_no為11。
第二個update將主鍵id為66及記錄更新為666,執行的代碼邏輯跟第一次update類似,但在唯一性約束檢查時需要分別判斷heap_no為7和11的記錄,并進一步獲取heap_no為8的記錄('1','7')。代碼執行過程如下:
1、首先會將已經存在的當前記錄調用btr_cur_del_mark_set_sec_rec刪除掉;
上圖確認操作的索引的detail7_1。
進一步確認刪除的記錄heap_no是11。
2、接下來會插入一條新的記錄,在插入前會進行唯一性約束檢查;
上圖的調用棧最下面的紅框表明此update操作進入了insert邏輯。中間紅框表明進行的是唯一性約束檢查。最上面的框表示當前處理的索引是detail7_1,heap_no為7表示找到的記錄是id=6那條最早的記錄對應的detail7_1索引記錄。執行c讓其繼續執行:
上圖可以發現還是在row_ins_scan_sec_index_for_duplicate中,heap_no為11表示處理的是id=66的那條剛刪除的記錄對應的detail7_1索引記錄。
也就是說我們構造出了二級唯一索引存在2個delete-marked但n_uniq相同(都為('1','6'))的記錄。讓gdb繼續執行:
還是在row_ins_scan_sec_index_for_duplicate中,此時處理的是heap_no為8的記錄,對應的索引變為('1','7'),唯一性約束檢查可以結束了。讓gdb繼續:
可以發現,此時已經進入到最后一個普通二級索引detail7_2的處理流程。
從上面構造的場景至少可以說明二級唯一索引存在索引鍵值相同的多條記錄。所以在唯一性約束檢查時需要使用while循環不斷獲取游標中的下一條記錄,直到發現索引鍵值不同的記錄,如果該記錄被其他事務鎖住,那么就會導致當前事務阻塞并引發鎖超時。
主鍵索引場景
該場景我們只需要構造不更新主鍵id,而是更新二級索引列或普通列,觀察是否會進入btr_cur_del_mark_set_clust_rec。所以我們嘗試對主鍵id為4的記錄做如下更新:
1、更新二級索引列:
session1-ddb>update dt set coupon_id='2' where id = 4;
在對主鍵索引調用row_upd_changes_ord_field_binary_func函數判斷后,并沒有進入delete-marked流程,而是馬上操作二級索引了,可以發現detail7_1索引的記錄需要更新。
2、更新普通列:
主鍵索引不需要delete-marked,唯一索引detail7_1也不需要。普通索引detail7_2需要。
上面就是簡單的GDB調試證明過程。對于二級唯一索引的證明是充分的,因為只需要有這種場景就行。但對主鍵索引的證明是不充分的,因為我們并沒有舉例排除所有可能的場景。
前面3篇文章分析了RC隔離級別下并發insert鎖超時問題。細心的同學是否發現在二級唯一索引進行唯一性沖突檢查時,加的是next-key共享鎖。那么為什么要加共享鎖呢,RC下不應該是no gap鎖嗎?這個問題比較有意思,我們在第四篇來分析。
原文鏈接:MySQL RC級別下并發insert鎖超時問題 - 案例驗證
總結
以上是生活随笔為你收集整理的insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#.NET中的事件2
- 下一篇: mingw + msys 上编译 ffm