Postgresql死锁问题

时间:2016-01-17 09:51:56

标签: postgresql deadlock

我在pg_log中收到以下死锁错误:

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);

1 个答案:

答案 0 :(得分:0)

我认为bb_batter_season_stat中至少有2条记录具有相同的bb_players_id

  1. 事务一被锁定以更新第一条记录。
  2. 交易二锁定了第二个。
  3. 交易一试图锁定第二个,但被阻止等待交易二。
  4. 事务二试图锁定第一条记录,但被阻止等待事务一,造成死锁。
  5. 为避免这种情况,您应该按主键的顺序强制锁定记录。例如,使用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);