问题描述
给出以下触发器:
CREATE OR REPLACE TRIGGER TR_MY_TRG_NAME
AFTER UPDATE OF COL_A,COL_B,COL_C ON T_MY_TABLE_Y
FOR EACH ROW
BEGIN
UPDATE T_MY_TABLE_X X
SET
X.COL_A = :NEW.COL_A,X.COL_B = :NEW.COL_B,X.COL_C = :NEW.COL_C
WHERE
X.ID = :NEW.ID;
END;
...并在T_MY_TABLE_Y中给出了200万条现有记录。
问题: 如果我的应用更改了所有2条mio记录(例如COL_A),那么在没有触发器的情况下,它会运行2-3分钟,而在使用触发器的情况下,则需要40分钟。
问题: 我可以尝试一些替代方法吗?
解决方法
另一种方法是在单个语句中更新T_MY_TABLE_X
,而不必强制触发器触发200万行中的每行并(可能)执行上下文切换。
因此:当您更新T_MY_TABLE_Y
时,请为UPDATE
重用相同的T_MY_TABLE_X
(必要时进行一些修改)。
我认为您可以通过分成三部分来更新DML的负载,以便为每个单独的列进行更新:
const firestore = firebase.firestore()
const ref = firestore.collection('messages').doc('foo')
ref.set({
createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
这样,Update可能不会在每次发生时都出现在每一列中。
此外,请确保CREATE OR REPLACE TRIGGER TR_MY_TRG_NAME
AFTER UPDATE OF COL_A,COL_B,COL_C ON T_MY_TABLE_Y
FOR EACH ROW
BEGIN
IF :NEW.COL_A != :OLD.COL_A THEN
UPDATE T_MY_TABLE_X SET COL_A = :NEW.COL_A WHERE ID = :NEW.ID;
END IF;
IF :NEW.COL_B != :OLD.COL_B THEN
UPDATE T_MY_TABLE_X SET COL_B = :NEW.COL_B WHERE ID = :NEW.ID;
END IF;
IF :NEW.COL_C != :OLD.COL_C THEN
UPDATE T_MY_TABLE_X SET COL_C = :NEW.COL_C WHERE ID = :NEW.ID;
END IF;
END;
上有索引,最好是唯一索引。
我没有时间写出代码,但是我建议尝试使用一种概述方法,以创建一个ARRAY
和RECORD
中的ID
的程序包, COL_A
,COL_B
和COL_C
。
BEFORE
语句触发器应实例化并初始化包和其中的数组,例如:
the_package.pr_init
ROW LEVEL
触发器应仅将:NEW.ID,:NEW.COL_A,:NEW.COL_B,:NEW.COL_C写入包中的数组,例如:
the_package.pr_save ( :NEW.ID,:NEW.COL_A,:NEW.COL_B,:NEW.COL_C )
然后,AFTER
语句触发器应该在驱动程序包内的数组上发出BULK UPDATE
,并清除ARRAY
,例如:
the_package.pr_do_update
。
这种方法的好处是,无论有多少行,您都只能执行一个附加的UPDATE语句。
该解决方案也包含在一个软件包中,尽管它在3个触发器之间展开,但是触发器代码本身将大大简化。