2016-01-17 25 views
0

我收到以下錯誤僵局在pg_log:PostgreSQL的僵局問題

2016-01-15 09:52:48.648 EST,"name","name",11694,"ip:40273",56988e35.2dae,1,"UPDATE",2016-01-15 01:14:13 EST,10/3886,49775,ERROR,40P01, 
"deadlock detected", 

"Process 11694 waits for ShareLock on transaction 49774; blocked by process 11685. 

Process 11685 waits for ShareLock on transaction 49775; blocked by process 11694. 

Process 11694: update bb_batter_season_stat set a_field=a_field+$1, ab_int=ab_int+$2, abvsl=abvsl+$3, abvsr=abvsr+$4, bbvsl=bbvsl+$5, bbvsr=bbvsr+$6, cs=cs+$7, 
cs_field=cs_field+$8, ... where bb_players_id=$53 

Process 11685: update bb_batter_season_stat set a_field=a_field+$1, ab_int=ab_int+$2, abvsl=abvsl+$3, abvsr=abvsr+$4, bbvsl=bbvsl+$5, bbvsr=bbvsr+$6, cs=cs+$7, 
cs_field=cs_field+$8, ... where bb_players_id=$53","See server log for query details.",,,, 

"update bb_batter_season_stat set a_field=a_field+$1, ab_int=ab_int+$2, abvsl=abvsl+$3, 
abvsr=abvsr+$4, bbvsl=bbvsl+$5, bbvsr=bbvsr+$6, cs=cs+$7, cs_field=cs_field+$8, ... where bb_players_id=$53",,,"" 

我不明白爲什麼會發生。運行相同查詢和死鎖的兩個進程發生。

表架構是:

CREATE TABLE bb_batter_season_stat (
    id SERIAL NOT NULL , 
    bb_players_id INTEGER NOT NULL , 
    G SMALLINT , 
    ABvsL SMALLINT , 
    ABvsR SMALLINT , 
    RvsL SMALLINT , 
    RvsR SMALLINT , 
    HvsL SMALLINT , 
    HvsR SMALLINT , 
    d2BvsL SMALLINT , 
    d2BvsR SMALLINT , 
    ... 
PRIMARY KEY(id) , 
    FOREIGN KEY(bb_players_id) REFERENCES bb_players(id)); 

CREATE INDEX bb_batter_season_stat_FKIndex1 ON bb_batter_season_stat (bb_players_id); 
+0

@JoachimIsaksson同樣的查詢同一個表。不同的進程在同一時間進行更新。是的,都在他們自己的交易中。你問是否有另一個查詢在該表上運行? – maximus

+1

在您的代碼中找到這些更新,並向我們顯示此代碼。可能是在一個事務中執行了兩個更新,一個更新'bb_batter_season_stat'表,另一個'bb_players' – krokodilko

+0

看起來這些事務已經在發生死鎖之前更新了'bb_batter_season_stat'中的一些行。向我們展示代碼。 –

回答

0

我想你在bb_batter_season_stat具有相同bb_players_id至少有2條記錄。

  1. 交易一鎖定更新第一條記錄。
  2. 交易二鎖定第二。
  3. 交易一試圖鎖定第二個,但被阻止等待交易二。
  4. 事務二試圖鎖定第一條記錄,但被阻塞等待事務一,造成死鎖。

爲了避免這種情況,您應該強制按主鍵的順序鎖定記錄。例如使用select for update

with ids as (
    select id 
    from bb_batter_season_stat 
    where bb_players_id=? 
    order by id 
    for update 
) 
update bb_batter_season_stat 
    set a_field=a_field+$1, ab_int=ab_int+$2, … 
    where id in (select id from ids); 
+1

有趣的想法,但我檢查 - 沒有重複的行(按列bb_players_id) – maximus