【问题标题】:Oracle Trigger Autonomous Transaction Missing RowsOracle 触发自治事务丢失行
【发布时间】:2015-01-27 02:53:38
【问题描述】:

我有两个表:delivery_records 和delivery_summary。我已经简化了表格来演示

select *
from delivery_records

FILTERLIST   PRICE_DATE   PRICE_VALUE
-------------------------------------
FL_1         1/1/2015     1
FL_1         1/1/2015     2
FL_1         1/1/2015     3
FL_2         1/1/2015     8
FL_2         1/1/2015     9

在对delivery_records 上的每一行进行插入或更新后,我有一个触发器,它会触发过程summarize_records,以便在每次修改delivery_records 表后立即更新delivery_summary 表。

CREATE OR REPLACE TRIGGER SNAPSHOT_TRIG
  AFTER INSERT OR UPDATE ON DELIVERY_RECORDS FOR EACH ROW

Declare

    PRAGMA AUTONOMOUS_TRANSACTION;

BEGIN

    dbms_output.put_line('Starting trigger');

    SUMMARIZE_RECORDS(:new.filterlist, trunc(sysdate));

    COMMIT;

    dbms_output.put_line('Trigger ended');


EXCEPTION
    WHEN OTHERS THEN
            dbms_output.put_line('SQL Error: ' || SQLCODE || ' - ' || SUBSTR(SQLERRM, 1, 100));


END DELIV_SNAPSHOT_UPDATE;

过滤列表是一组相关的交付记录。 summarise_records 存储过程通过在 delivery_records 表上运行 select 然后将结果插入到 delivery_summary 表中来汇总每个日期的每个过滤器列表的交付计数,我希望这会产生以下结果:

select * from delivery_summary

FILTERLIST DATE       DELIVERY_COUNT
------------------------------------
FL_1       1/1/2015   3
FL_2       1/1/2015   2

这按预期工作,但似乎触发器缺少为每个过滤器列表插入的最后一条记录。几乎就像触发器没有触发一样。我做了一些研究,有人暗示自治事务看不到当前事务的记录。这是我看到的表格,除非我运行某种无操作更新以导致触发器再次触发。

select * from delivery_summary

FILTERLIST DATE       DELIVERY_COUNT
------------------------------------
FL_1       1/1/2015   2
FL_2       1/1/2015   1

据我了解,作为“后”触发器,该行对于我的摘要过程应该是可见的。我必须将程序设置为 pragma 自治,因为我在正在触发的表上进行选择。我知道这是禁忌,但这似乎是满足实时汇总表要求的唯一方法。

有没有更好的方法来做到这一点?这似乎是触发器的完美用例。

【问题讨论】:

  • 使用视图可能比尝试使用触发器维护摘要状态更容易。
  • 我支持使用视图或可能是物化视图的建议。取决于delivery_records 表的更新频率与delivery_summary 表的查看频率。
  • 不幸的是,我遗漏了很多外围功能,因此这不会是一个荒谬的长问题。在交付记录的数量和在视图上报告和汇总的列数之间并不能提供所需的性能。并且某些列被冻结(未更新)历史日期以提供审计日志。视图无法提供此功能。
  • @AndyIngraham - 物化视图可能,但是是的,这取决于summarize_records 在做什么。当然,触发器有其自身的性能损失,尤其是当您最终有多个插入尝试更新同一个摘要时。无论如何,不​​,即使在后触发器中,您插入的数据对自治事务也不可见 - 这就是使其自治的原因,因为它在当前(未提交的)事务之外。

标签: oracle triggers


【解决方案1】:

在这种情况下,我认为使用AUTONOMOUS_TRANSACTION 注释是错误的,因为:

在一项交易中,您正在更新 delivery_records 和 您将该事务标记为分离的(通过使用 pragma AUTONOMOUS_TRANSACTION)从中读取数据 delivery_records,在。

所以我更喜欢不使用 AUTONOMOUS_TRANSACTION 并将程序代码带入触发器中,并在那里直接计算所需值并将其插入delivery_summary

【讨论】:

  • 不幸的是,我需要从 delivery_records 表中获取与正在插入或更新的当前记录相关的其他记录。
【解决方案2】:

您可以使用语句触发器,即跳过FOR EACH ROW

在您的触发器中,您必须这样做(仅考虑更新):

UPDATE delivery_summary
SET (FILTERLIST, DATE, DELIVERY_COUNT) = 
    (SELECT FILTERLIST, DATE, COUNT(*) 
    FROM delivery_records
    GROUP BY FILTERLIST, DATE);

但是,更好的解决方案是将所有这些放入存储过程中并调用此过程而不是使用触发器。

【讨论】:

  • 我正在调用一个存储过程,它与上面的代码非常相似(尽管更复杂)。我面临的问题是 count() 正在返回 expected_count - 1。这就像当前记录不存在于 count()
  • 你是不是又用了一些AUTONOMOUS_TRANSACTION
  • 不,我在触发器中声明了autonomous_transaction,但没有在过程中声明。是不是我在错误的地方有自治事务声明?
  • 也许我的建议不清楚:删除 所有 触发器并按程序执行所有操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-09
  • 2011-11-20
  • 2012-03-23
  • 2011-09-30
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
相关资源
最近更新 更多