Триггеры DB2 for i - один раз на оператор, но сравнивают значения до и после - PullRequest
0 голосов
/ 21 марта 2019

В DB2 для IBM i возможно ли создать триггер, который запускается один раз для каждого оператора, но может циклически проходить по всем затронутым строкам, чтобы определить, действительно ли были изменены какие-либо значения?

Вариант использования - обновитьМатериализованная таблица запросов (MQT) с триггером на базовые таблицы.Но мы хотим обновить MQT, только если значения действительно изменились.Если мы создадим триггер для запуска один раз в строке, мы сможем получить желаемую функциональность.Но если мы вставляем, обновляем и / или удаляем несколько строк одновременно, оператор «Обновить» выполняется для каждой строки.И в настоящее время это занимает около 10 секунд для этого MQT в нашей системе.

Просто надеясь, что есть способ использовать триггер, установленный для запуска один раз для каждого оператора, и при этом иметь доступ к значениям до и после каждой отдельной строки.Я не смог найти ничего, что указывало бы, возможно это или нет.Хотя я подозреваю, что это не так.

Если есть какой-то другой способ автоматического обновления MQT эффективным образом, я также открыт для этого.

Ответы [ 3 ]

1 голос
/ 21 марта 2019

Да, документация здесь . Однако, в зависимости от того, как вы пытаетесь это сделать, между командой IBM i ADDPFTRG и SQL CREATE TRIGGER.

есть некоторые различия.

ADDPFTRG не поддерживает триггеры уровня оператора, но CREATE TRIGGER поддерживает.

При использовании триггера уровня оператора вы можете ссылаться на соответствующие строки с помощью

REFERENCING OLD TABLE AS ___
            NEW TABLE AS ___

Вы можете обрабатывать старые и новые ссылки на таблицы с помощью операторов SQL, как если бы они были обычными таблицами.

Просто чтобы прояснить, OLD TABLE ссылается на затронутые строки так, как они были до выполнения инструкции SQL, а NEW TABLE ссылается на затронутые строки так, как они будут после завершения статута SQL.

0 голосов
/ 22 марта 2019

Я не думаю, что имеет смысл запускать триггер для обновления ...

Весь смысл триггера + MQT состоит в том, чтобы триггер напрямую обновлял таблицу MQT. Таким образом, вам нужно иметь дело только с точными строками, которые изменились; вместо того, чтобы заставлять БД снова читать всю базовую таблицу.

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 действительно обновлено.

Если за один раз выполняются обновления SQL, а не однострочных обновлений RPG (или 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))

Приведенный выше пример взят из статьи Ускоренная аналитика - более быстрые агрегации с использованием технологии кодированного векторного индекса (EVI) IBM DB2 for i . Это хорошая статья, которая сравнивает EVI с MQT для хранения агрегатов.

0 голосов
/ 21 марта 2019

Пример:

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@
...