我有以下触发器,其中
daily_shifts_tab
和 daily_shifts_wfv
是相同的表,并且触发器将数据从 daily_shifts_wfv
同步到 daily_shifts_tab
。
这里的问题是,当应用程序中的删除更加频繁时,
delete
上的语句会导致元组锁定。从应用程序中删除语句是daily_shifts_tab
delete from daily_shifts_tab where OBJECTID = $1;
是对
id,objectid
和daily_shifts_tab
的PK。该语句导致锁定元组。我不明白为什么会发生元组锁。
如何解决问题?daily_shifts_wfv
CREATE OR REPLACE FUNCTION daily_shifts_aiudr()
RETURNS trigger AS $body$
BEGIN
if (TG_OP = 'INSERT') then
INSERT INTO daily_shifts_wfv (
id,
OBJECTID,
PFID,
INTIME,
OUTTIME)
VALUES(new.id,
new.OBJECTID,
new.pfid,
new.INTIME,
new.OUTTIME
) ON CONFLICT (id,pfid,intime,scheduletype,schedtempassignoid)
DO NOTHING;
RETURN NEW;
elsif (TG_OP = 'UPDATE') then
update daily_shifts_wfv
set pfid = new.pfid,
intime = new.intime,
outtime = new.outtime
where id = current_setting('ctx_ng_vpd.ctx_id_fil')
and OBJECTID = old.OBJECTID;
RETURN NEW;
elsif (TG_OP = 'DELETE') then
delete from daily_shifts_wfv
where id = current_setting('ctx_ng_vpd.ctx_id_fil')
and OBJECTID = old.OBJECTID;
RETURN OLD;
end if;
END; $body$ LANGUAGE plpgsql;
:我的猜测是,您遇到了这样的问题:CREATE TRIGGER daily_shifts_aiudr
AFTER INSERT OR UPDATE OR DELETE
ON daily_shifts_tab
FOR EACH ROW
EXECUTE PROCEDURE daily_shifts_aiudr();
上具有大量有效负载的N行的单个操作会转换为
daily_shifts_tab
上的N个此类操作。Postgres 执行所有相同的操作,并在两个表上锁定所有相同的操作,但它需要更长的时间,并且因此锁定在 daily_shifts_wfv
上挂起的时间更长。您可以尝试将您的
行级触发器切换为a每语句触发器,它只是回显其他表上的主语句,看看是否可以解决您的问题:
daily_shifts_wfv
CREATE OR REPLACE FUNCTION daily_shifts_aiudr()RETURNS trigger AS $body$
BEGIN case TG_OP WHEN 'INSERT' then
INSERT INTO daily_shifts_wfv (
id,
OBJECTID,
PFID,
INTIME,
OUTTIME)
SELECT newdata.id,
newdata.OBJECTID,
newdata.pfid,
newdata.INTIME,
newdata.OUTTIME
FROM newdata
ON CONFLICT (id,pfid,intime,scheduletype,schedtempassignoid)
DO NOTHING;
when 'UPDATE' then
update daily_shifts_wfv as target
set pfid = newdata.pfid,
intime = newdata.intime,
outtime = newdata.outtime
from newdata
join olddata using(OBJECTID)
where target.id = olddata.id
and target.OBJECTID = olddata.OBJECTID;
when 'DELETE' then
delete from daily_shifts_wfv as target
using olddata
where target.id = olddata.id
and target.OBJECTID = olddata.OBJECTID;
end case;
RETURN NULL;--doesn't matter in a statement-level trigger
END; $body$ LANGUAGE plpgsql;
您可以看到
CREATE TRIGGER daily_shifts_aiudr_insert
AFTER INSERT
ON daily_shifts_tab
REFERENCING NEW TABLE as newdata
FOR EACH STATEMENT
EXECUTE PROCEDURE daily_shifts_aiudr();
CREATE TRIGGER daily_shifts_aiudr_update
AFTER UPDATE
ON daily_shifts_tab
REFERENCING OLD TABLE as olddata NEW TABLE as newdata
FOR EACH STATEMENT
EXECUTE PROCEDURE daily_shifts_aiudr();
CREATE TRIGGER daily_shifts_aiudr_delete
AFTER DELETE
ON daily_shifts_tab
REFERENCING OLD TABLE as olddata
FOR EACH STATEMENT
EXECUTE PROCEDURE daily_shifts_aiudr();
上的操作在
daily_shifts_tab
上重复 - 唯一的区别是现在是一次性应用整个操作,而不是逐行应用。daily_shifts_wfv
对象ID | pfid | 银泰时代 | 超时 | 日程类型 | schedtempassignoid | |
---|---|---|---|---|---|---|
2 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 | |
3 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 | |
4 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 |
insert into daily_shifts_tab
(id, OBJECTID, PFID, INTIME, OUTTIME,scheduletype,schedtempassignoid)values
(2,2,1,now()-'1 min'::interval,now(),1,1)
,(3,3,1,now()-'1 min'::interval,now(),1,1)
,(4,4,1,now()-'1 min'::interval,now(),1,1);
select * from daily_shifts_wfv;
对象ID | pfid | 银泰时代 | 超时 | 日程类型 | schedtempassignoid | |
---|---|---|---|---|---|---|
3 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 | |
4 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 |
delete from daily_shifts_tab
where (id, OBJECTID)=(2,2);
select * from daily_shifts_wfv;
对象ID | pfid | 银泰时代 | 超时 | 日程类型 | schedtempassignoid | |
---|---|---|---|---|---|---|
4 | 1 | 2024-12-13 09:39:24.253247+00 | 2024-12-13 09:40:24.253247+00 | 1 | 1 | |
3 | 1 | 无穷大 | 2024-12-13 09:40:24.253247+00 | 1 | 1 |