PostgreSQL死鎖案例分析(二)
阿新 • • 發佈:2022-12-01
PostgreSQL死鎖案例分析(二)
原作者:陳雁飛 創作時間:2019-09-26 15:28:14+08 採編:wangliyun
釋出時間:2019-09-27 08:08:14
歡迎大家踴躍投稿,投稿信箱:[email protected]
評論:1 瀏覽:4684
作者介紹
陳雁飛,開源PostgreSQL愛好者,一直從事PostgreSQL資料庫運維工作
問題現象
接前一篇文章,這裡繼續介紹在工作中遇到的一個死鎖案例。經過對業務模型的抽取分析(後面會介紹表結構和資料,業務模型來源於開源元件的實際業務),模擬得到的死鎖日誌資訊如下:
2019-09-01 21:01:08.359 CST [1482] ERROR: deadlock detected 2019-09-01 21:01:08.359 CST [1482] DETAIL: Process 1482 waits for ShareLock on transaction 523; blocked by process 1610. Process 1610 waits for ShareLock on transaction 524; blocked by process 1482. Process 1482: select test2.a,test2.b,test2.c from test2 join test1 on test2.a = test1.a where test2.b = 2 and test1.c = 3 for update; Process 1610: delete from test1 where a = 1; 2019-09-01 21:01:08.359 CST [1482] HINT: See server log for query details. 2019-09-01 21:01:08.359 CST [1482] CONTEXT: while locking tuple (0,1) in relation "test1" 2019-09-01 21:01:08.359 CST [1482] STATEMENT: select test2.a,test2.b,test2.c from test2 join test1 on test2.a = test1.a where test2.b = 2 and test1.c = 3 for update;
從資料庫日誌上看,記錄的SQL語句涉及兩張表TEST1和TEST2,其中一個事務執行的SQL是SEELCT … FOR UPDATE用於獲取行級鎖操作。
流程梳理
經分析,事務操作涉及兩張表,簡化後的表結構以及操作邏輯如下:
create table test1(a int primary key, b int, c int); create table test2(a int references test1 on delete cascade,b int, c int); insert into test1 values(1,2,3),(2,3,4),(3,4,5); insert into test2 values(1,2,3),(2,3,4),(3,4,5);
表TEST1
表TEST2
從表結構上可以看到,表test2和test1構成外來鍵約束關係,並且是級聯刪除的關係,導致在刪除TEST1表中的時候,資料庫會自動請求對TEST2表中對應行的刪除操作。根據業務操作模型,整理得到的執行SQL邏輯如下(這裡僅僅列舉出事務中涉及鎖相關的操作,其他查詢操作未列舉出):
從整理的SQL操作上看,事務一僅僅涉及到對TEST1表的操作,但是由於存在外來鍵級聯刪除的關係,在delete語句的執行的時候,會請求TEST2表相應的行進行刪除。事務二主要是一個SELECT .. FOR UPDATE操作,但是查詢語句中涉及兩表join關聯,且最後鎖定的行和事務一中請求的TEST2表相同。因此,可以推測事務二執行的時候,依次涉及對TEST2表和TEST1表的加鎖操作。
由於是涉及到行級鎖的操作,需要藉助gdb工具進行除錯,控制事務2獲取鎖的邏輯順序。首先,根據執行計劃資訊,找到載入的行級鎖的函式。
在資料庫中,SQL的執行按照生成的執行計劃完成的,該執行計劃中最頂層運算元是LockRows,對應到執行器中的函式是ExecLockRows,結合程式碼,對行級元素加鎖的操作如下:
test = table_tuple_lock(erm->relation, &tid, estate->es_snapshot,
markSlot, estate->es_output_cid,
lockmode, erm->waitPolicy,
lockflags,
&tmfd);