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 来存储聚合。
在 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 来存储聚合。