DB2 for i 触发器 - 每个语句一次,但比较前后值

DB2 for i Triggers - Once per statement, but comparing before and after values

在 DB2 for IBM i 中,是否可以创建一个触发器,每个语句 运行 一次,但能够遍历所有受影响的行以确定是否有任何值实际更改?

用例是使用基础表上的触发器更新具体化查询 Table (MQT)。但我们只想在值实际发生变化时刷新 MQT。如果我们每行创建一次 运行 的触发器,我们就能获得所需的功能。但是如果我们Insert, Update and/or Delete 一次多行,"Refresh" 语句每行运行s。目前,我们系统上的这个 MQT 大约需要 10 秒。

只是希望有一种方法可以在每个语句中使用一次设置为 运行 的触发器,但仍然可以访问每个单独行的前后值。我一直无法找到任何表明它是否可能的东西。虽然我怀疑不是。

如果有其他方法可以有效地自动刷新 MQT,我也愿意接受。

是的,文档是 here。但是,根据您尝试执行此操作的方式,IBM i 命令 ADDPFTRG 和 SQL CREATE TRIGGER.

之间存在一些差异

ADDPFTRG 似乎不支持语句级触发器,但 CREATE TRIGGER 支持。

使用语句级触发器时,您可以使用

引用受影响的行
REFERENCING OLD TABLE AS ___
            NEW TABLE AS ___

您可以使用 SQL 语句处理新旧 table 引用,就像它们是常规 table 一样。

明确一点,OLD TABLE 引用受影响的行,因为它们在 SQL 语句 运行 和 NEW TABLE 引用受影响的行,因为它们将在 SQL 语句完成后出现。

示例:

create table test (id int not null primary key, a int)@
create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

insert into test values (1, 1), (2, 1), (3, 1) with nc@

create or replace trigger test_aus 
after update on test
referencing 
new table as n
old table as o
for each statement
mode db2sql
begin atomic
  if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
    refresh table test_mqt;
  end if;
end@

-- trigger IS NOT fired after the following update
update test set a=1 with nc@
-- the following select returns 0
select cnt from test_mqt@

-- trigger IS fired after the following update
update test set a=2 with nc@
-- the following select returns 6
select cnt from test_mqt@

我认为触发 运行 刷新没有意义...

触发器 + MQT 的全部意义在于让触发器直接更新 MQT table。这样你只需要处理发生变化的确切行;而不是强制数据库再次读取整个基数 table。

create or replace trigger test_aus 
after update on test
referencing 
new row as n
old row as o
for each row
mode db2sql
begin atomic
  if n.a <> o.a then
    update test_mqt set cnt = cnt + n.a - o.a;
  end if;
end@

但是请注意,如果您只对 a 中的更改感兴趣,那么您可以将触发器定义为

after update of a on test 
for each row 

这样触发器只会在 a 实际更新时触发。

如果与 RPG(或 SQL)单行更新相比,一次更新设置的SQL更多,那么语句触发器可能是值得的...

大概是这样:

create or replace trigger test_aus 
after update on test
referencing 
new table as n
old table as o
for each statement
mode db2sql
begin atomic
   update test_mqt 
     set cnt = cnt + (select sum(n.a - o.a) 
                        from N join O using(id)
                        where n.a <> o.a
                      );

end@

编辑:MQT 的替代方案
我实际上从未在生产中使用过 MQT,因为 IBM i 不支持系统维护的 MQT。

在您对更新的聚合感兴趣的情况下,包含聚合的编码矢量索引 (EVI) 可能会提供更好的解决方案;因为它们是自动维护的。

CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
ON sales_fact(sale_location_id ASC) 
INCLUDE(SUM(sale_amount_measure))

上面的例子来自文章Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology。这是一篇很好的文章,比较了 EVI 和 MQT 来存储聚合。