我正试图在我们的制作中解决这个死锁问题,现在我真的需要一些帮助。
PostgreSQL 9.5.10
查询1 :(更新1000条记录)
update entitlements.stream_general sg
set stream_offset_id =nextval( 'entitlements.stream_general_stream_offset_id_seq' ),
should_update_offset_id = false
from (select id, topic, stream_id from entitlements.stream_general where should_update_offset_id = true limit 1000) sg2
where sg.id=sg2.id and sg.topic=sg2.topic and sg.stream_id = sg2.stream_id
查询2 :(更新单个记录)
update entitlements.stream_general set stream_action = $1::entitlements.stream_action_type, update_dt = now(), should_update_offset_id = true where stream_id = $2 and topic = $3 and id = $4
例外:
Process 60563在事务3603536083上等待ShareLock;受阻 进程60701.进程60701等待事务上的ShareLock 3603536039;被流程60563阻止。
由于死锁进程中只涉及两个事务,因此一个Update如何与另一个Update处于死锁状态。根据我的理解,在第一次更新后,所有这些行上都会有RowExclusiveLock,第二次更新应该被阻止。怎么会有DEADLOCK?
stream_general
表架构:
CREATE TABLE entitlements.stream_general (
stream_id int4 NOT NULL,
id varchar NOT NULL,
topic varchar NOT NULL,
stream_offset_id int8 NOT NULL DEFAULT '-1'::integer,
create_dt timestamptz NOT NULL DEFAULT now(),
update_dt timestamptz NOT NULL DEFAULT now(),
stream_action stream_action_type NOT NULL,
should_update_offset_id bool NULL,
PRIMARY KEY (stream_id, topic, id),
FOREIGN KEY (stream_id) REFERENCES entitlements.stream(stream_id) ON DELETE CASCADE
)
WITH (
OIDS=FALSE
) ;
CREATE INDEX stream_general_id_idx ON entitlements.stream_general USING btree (id, topic) ;
CREATE INDEX stream_general_should_update_offset_id_index ON entitlements.stream_general USING btree (should_update_offset_id) ;
CREATE INDEX stream_general_stream_id_idx ON entitlements.stream_general USING btree (stream_id, topic, stream_offset_id) ;
注意:stream_id是外键。
我能想到的唯一问题是Query1中的子查询,但我怎么也无法弄清楚Select如何成为问题。或者可能是外国约束的东西。
答案 0 :(得分:1)
第一个查询在进行写锁定之前首先进行读锁定。当第二个查询也等待写锁时,这会导致死锁吗?
尝试for update
让子查询获得写锁定吗?
update ...
from (
select ...
from ...
FOR UPDATE
) sg2