如何优化批量插入场景的触发器?

Posted

技术标签:

【中文标题】如何优化批量插入场景的触发器?【英文标题】:How can I optimise my trigger for bulk insert scenario? 【发布时间】:2020-11-05 13:49:34 【问题描述】:

我创建了一个触发器,它根据另一列 (colY) 中的值更新表中的列 (比如 colX)。 colY 可以插入或更新,如果 colX 为空,则应将其设置为 colY 的值。问题是我有一个文件上传,它在此表中插入大量记录并填充 colY。大多数情况下 colX 也已填充,但如果未填充,我希望此触发器为我完成。这是我的触发器:

CREATE OR REPLACE TRIGGER T_FILLCOLY
BEFORE INSERT OR UPDATE ON TAB1
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW

DECLARE
    
BEGIN
if (:new.COLX is not null and :new.COLY is null) then 
:new.COLY:= :new.COLX;
end if;

if (:new.COLA is not null and :new.COLBis null) then 
:new.COLB := :new.COLA;
end if;

END;
/

有什么方法可以让这个触发器更快?现在上传时间是没有触发器的情况下的两倍。谢谢。

【问题讨论】:

我认为不会提供更快的案例,因为没有 DML,因此当前操作没有成本。顺便说一句,你真的认为这样的设计吗,因为持有一个已经可以从其他列中计算出来的列,几乎没有意义。 我不确定,但请尝试 when 子句并将您的两个条件都放在 OR 中并使用相同的触发器进行检查。 嗨@BarbarosÖzhan 我同意,这不是最佳方法。我正在使用一个已经投入生产的系统并且没有很多选择。我们目前所做的另一个选项是在上传后运行更新查询,而且速度非常快。唯一的缺点是它的手册,我们有忘记运行脚本的风险。触发器可以避免这种情况。 触发器本质上是逐行操作,而您之前执行的更新是批量操作。我最好的猜测是触发器总是会慢很多,只是因为这个基本的区别。 感谢您的回复@pmdba,我也很怀疑。我希望如果有什么我可以做的事情可以使触发器在所有行都更新后执行。我知道这不是语句级触发器的正确​​候选者,但也许还有其他类似的东西。 【参考方案1】:

您可以尝试单独保留 colx 和 coly(无触发器)并定义第三个虚拟列,该列显示您的 null 逻辑的结果。这应该会使您的加载时间恢复到原来的水平,但代价是必须在查询时执行该逻辑。您还可以尝试禁用触发器、执行加载、使用空逻辑更新表,然后启用触发器。这可能会运行得更快一些。

【讨论】:

我不明白删除/禁用触发器的部分。那意味着目的没有解决对吗?我仍然需要通过此触发器或其他方式填充 colY 的功能。我们目前使用需要手动执行的更新脚本,我试图避免这种情况,因为我们可能会忘记这样做。【参考方案2】:

您多久加载一次此批量文件?如果这是一次性练习 - 或通过程序运行的定期安排的工作 - 这是另一种方法。

    禁用触发器 上传批量文件 使用基于集合的 UPDATE 语句将业务规则应用于上传的记录 重新启用触发器

基于集合的操作应该比触发器的逐行触发更快。但是,您可能需要调整该语句以获得令人满意的性能。您投入多少工作可能取决于您运行此流程的频率。

【讨论】:

我们已经这样做了。上传经常发生,并且在我们从外部系统接收文件时手动触发。我们查看触发器的唯一原因是避免忘记运行更新语句。 如果这是您经常做的事情,那么您应该编写脚本。代码不会“忘记”做某事。

以上是关于如何优化批量插入场景的触发器?的主要内容,如果未能解决你的问题,请参考以下文章

mysql小技能:批量插入性能优化

MySQL批量插入优化

JDBC批量插入数据优化,使用addBatch和executeBatch

MySql批量插入时,如何不插入重复的数据

使用 REST 优化 Neo4j 的大批量批量插入

Postgres 批量插入不同的模式