Re: Determining if a table really changed in a trigger

Поиск
Список
Период
Сортировка
От Mark Dilger
Тема Re: Determining if a table really changed in a trigger
Дата
Msg-id AD34DA0A-C6F4-4993-953C-36D7D973315D@enterprisedb.com
обсуждение исходный текст
Ответ на Re: Determining if a table really changed in a trigger  (Mitar <mmitar@gmail.com>)
Ответы Re: Determining if a table really changed in a trigger  (Mitar <mmitar@gmail.com>)
Список pgsql-general

> On Oct 26, 2021, at 1:34 PM, Mitar <mmitar@gmail.com> wrote:
>
> Hi!
>
> On Tue, Oct 26, 2021 at 10:17 PM Mark Dilger
> <mark.dilger@enterprisedb.com> wrote:
>> I can't tell from your post if you want the trivial update to be performed, but if not, would it work to filter
trivialupdates as: 
>
> No, I want to skip trivial updates (those which have not changed
> anything). But my trigger is per statement, not per row. So I do not
> think your approach works there? So this is why I am then making a
> more complicated check inside the trigger itself.

The trigger "my_table_trig" in the example is a per row trigger, but it exists only to demonstrate that the rule has
filteredout the appropriate rows.  You can use the rule "my_table_rule" as written and a per statement trigger, as
here:

rules=# create table my_table (i integer, j json);
CREATE TABLE
rules=# insert into my_table
rules-#   select gs::integer, '{"key":1}'::json
rules-#     from generate_series(1,3) gs;
INSERT 0 3
rules=# create function my_table_func () returns trigger as $$
rules$# declare
rules$#   have_rows boolean;
rules$# begin
rules$#   select true into have_rows from old_values limit 1;
rules$#   if have_rows then
rules$#     raise warning 'rows have changed';
rules$#   else
rules$#     raise warning 'no rows changed';
rules$#   end if;
rules$#   return null;
rules$# end
rules$# $$ language plpgsql;
CREATE FUNCTION
rules=# create trigger my_table_trig after update on my_table
rules-#   referencing old table as old_values
rules-#   for each statement
rules-#   execute function my_table_func();
CREATE TRIGGER
rules=# update my_table set j = '{"key":2}'::jsonb;
2021-10-26 13:51:58.139 PDT [34352] WARNING:  rows have changed
2021-10-26 13:51:58.139 PDT [34352] CONTEXT:  PL/pgSQL function my_table_func() line 7 at RAISE
WARNING:  rows have changed
UPDATE 3
rules=# create rule filter_trivial_updates as on update to my_table
rules-#   where new.i = old.i
rules-#     and new.j::jsonb = old.j::jsonb
rules-#   do instead nothing;
CREATE RULE
rules=# update my_table set j = '{"key":2}'::jsonb;
2021-10-26 13:51:58.143 PDT [34352] WARNING:  no rows changed
2021-10-26 13:51:58.143 PDT [34352] CONTEXT:  PL/pgSQL function my_table_func() line 9 at RAISE
WARNING:  no rows changed
UPDATE 0
rules=# update my_table set j = '{"key":3}'::jsonb;
2021-10-26 13:51:58.143 PDT [34352] WARNING:  rows have changed
2021-10-26 13:51:58.143 PDT [34352] CONTEXT:  PL/pgSQL function my_table_func() line 7 at RAISE
WARNING:  rows have changed
UPDATE 3

Note that there is a performance cost to storing the old rows using the REFERENCING clause of the trigger, so you'll
wantto think about all your various options and decide between them.  I am not in a position to make performance
recommendationsfor your schema.  However, if updates tend to be target at small sets of rows, and if the rule is used
tofurther filter out trivial updates, this might be cheap. 

Note that I used equality and inequality rather than IS DISTINCT FROM and IS NOT DISTINCT FROM in the design, but you
shouldthink about how NULL values (old, new, or both) will behave in the solution you choose. 

—
Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company






В списке pgsql-general по дате отправления:

Предыдущее
От: Mitar
Дата:
Сообщение: Re: Determining if a table really changed in a trigger
Следующее
От: Lucas
Дата:
Сообщение: Re: ZFS filesystem - supported ?