About rules
The test case
We have a simple table:
1 2 3 4 | CREATE UNLOGGED TABLE upd ( id integer NOT NULL , val text NOT NULL ) WITH (autovacuum_enabled = off ); |
Every update to this table should be logged to a second table:
1 2 3 4 5 6 | CREATE UNLOGGED TABLE log ( id integer NOT NULL , log_time timestamptz NOT NULL DEFAULT current_timestamp , new_val text NOT NULL ) WITH (autovacuum_enabled = off ); |
The test will repeatedly perform the following in a loop:
1 2 3 4 5 6 7 8 9 10 | TRUNCATE upd; TRUNCATE log; INSERT INTO upd (id, val) SELECT i, 'text number ' || i FROM generate_series(1, 100000) i; VACUUM (ANALYZE) upd; UPDATE upd SET val = val; |
baseline
UPDATE
(called “zero”), and one with just the UPDATE
, but no logging (called “base”). This will enable me to measure the net time spent in the UPDATE
by subtraction so I can calculate how much performance is slowed down by the different logging techniques.logging with a rule
For this measurement, which I call “rule”, I’ll use the following rule to log updates:
1 2 3 | CREATE RULE upd_rule AS ON UPDATE TO upd DO ALSO INSERT INTO log (id, new_val) VALUES (NEW.id, NEW.val); |
logging with a row level trigger
For this measurement, which I call “trig_row”, I’ll use the following trigger to log updates:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE FUNCTION upd_row_trig() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN INSERT INTO log (id, new_val) VALUES (NEW.id, NEW.val); RETURN NEW; END ;$$; CREATE TRIGGER upd_row_trig AFTER UPDATE ON upd FOR EACH ROW EXECUTE PROCEDURE upd_row_trig(); |
logging with a statement level trigger
For this measurement, which I call “trig_stmt”, I’ll use the following trigger to log updates:
1 2 3 4 5 6 7 8 9 10 11 12 | CREATE FUNCTION upd_stmt_trig() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN INSERT INTO log (id, new_val) SELECT id, val FROM newrows; RETURN NEW; END ;$$; CREATE TRIGGER upd_row_trig AFTER UPDATE ON upd REFERENCING NEW TABLE AS newrows FOR EACH STATEMENT EXECUTE PROCEDURE upd_stmt_trig(); |
This uses transition tables which are new in PostgreSQL v10. The REFERENCING
clause will make all rows modified by the statement available in a “temporary” table newrows
.
Test environment
psql -c "..."
. The script loops through the statements twenty times, and the elapsed time is measured with time
.Each test is executed three times to ensure that the execution time does not vary, then the middle value is used.
Test results
The zero measurements have been subtracted and the result divided by twenty to obtain the following numbers:
baseline | rule | row level trigger | statement level trigger | |
---|---|---|---|---|
execution time | 295 ms | 454 ms | 3816 ms | 642 ms |
overhead percentage | 0 % | 54 % | 1193 % | 117 % |
Discussion
So with PostgreSQL v10 we have a good alternative that performs half as well as rules, and there is no need to use rules unless you need cutting edge performance.
No comments:
Post a Comment
It’s all about friendly conversation here at small review :) I’d love to be hear your thoughts!
Be sure to check back again because I do make every effort to reply to your comments here.