Postgres 中的元组锁

问题描述 投票:0回答:1

我有以下触发器,其中

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;
	
postgresql
1个回答
0
投票
评论

:我的猜测是,您遇到了这样的问题: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每语句触发器,它只是回显其他表上的主语句,看看是否可以解决您的问题:
db<>fiddle 的演示 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


id234
对象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;

id34
对象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;

id43
对象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
© www.soinside.com 2019 - 2024. All rights reserved.