Thread: How to EXPLAIN a trigger function

How to EXPLAIN a trigger function

From
Zdeněk Bělehrádek
Date:
As part of our monitoring system we have a process that on every incomming
event inserts a row into a dummy table. This INSERT is intercepted by BEFORE
INSERT trigger that checks if the event matches some existing incident, if
yes, then it updates the incident data, else it creates a new incident.

There was a major malfunction in our network, and the system generated about
300 events per second. We found that during this eriod our monitoring
contained obsolete data, because the trigger bottlenecked whole system. We
would like to know if there is simple way to EXPLAIN the trigger function, so
we could optimize it.

We are using PostgreSQL 9.4.3. All processes are single-threaded and there
were no problems caused by concurrency anomalies (we checked by temporarily
using SERIALIZABLE - there were no failing transactions and the obsoleteness
was still there).

Simplified version looks like this:

CREATE TABLE dummytable (id int, data text, ...);
CREATE TABLE incidents (id int, data text, lastupdate timestamp, ...);

The monitoring process does:
INSERT INTO dummytable VALUES (id, data);

The trigger does
BEGIN
    SELECT id INTO vid FROM incidents WHERE field1 = NEW.field1 AND (field2 =
NEW.field2 OR field3 = NEW.field3);

    IF vid IS NULL THEN
        UPDATE incidents SET lastupdate = NOW();
    ELSE
        INSERT INTO incidents VALUES (id, data)
    END IF;

    RETURN NULL;
END;


The trigger took about 12 ms to do its work, as we found out by doing
EXPLAIN ANALYZE INSERT INTO dummytable;
so it was clearly a problem.

I looked the various Internet resources and found an information that stored
procedures are similar to prepared statements by computing the execution plan
once at creation time. We thought the first SELECT could use some suboptimal
plan and changed it to

EXECUTE 'SELECT id FROM incidents WHERE field1 = NEW.field1 AND (field2 =
NEW.field2 OR field3 = NEW.field3);' INTO vid USING ...;

We did it by trial and error, because we couldn't find any way to EXPLAIN the
trigger function. Is there any way to do it? For now we were lucky to hit the
right solution quickly, but in some future case we could waste many hours by
looking basically everywhere.

Notes:
* The SQL is simplified, because I am not very interested in finding solution
to this exact case. I want to "learn to fish" not have a "fish given to me".
* We could skip the trigger and just do it in application, but we fear about
the cost of round trips
* We are currently thinking about doing  the INSERTs in parallel, and we are
aware of potential problems with concurrent transaction


Re: How to EXPLAIN a trigger function

From
Albe Laurenz
Date:
Zdenek Belehrádek wrote:
> We
> would like to know if there is simple way to EXPLAIN the trigger function, so
> we could optimize it.

I believe that the auto_explain module could help you:
http://www.postgresql.org/docs/current/static/auto-explain.html

If you turn on "auto_explain.log_nested_statements" and set
"auto_explain.log_min_duration" low enough, the execution plans of
all SQL statements calle from a function will be logged.

Yours,
Laurenz Albe

Re: How to EXPLAIN a trigger function

From
Zdeněk Bělehrádek
Date:
Dne Po 17. srpna 2015 13:25:25, Albe Laurenz napsal(a):
> Zdenek Belehrádek wrote:
>
> > We
> > would like to know if there is simple way to EXPLAIN the trigger function,
> > so we could optimize it.
>
>
> I believe that the auto_explain module could help you:
> http://www.postgresql.org/docs/current/static/auto-explain.html
>
> If you turn on "auto_explain.log_nested_statements" and set
> "auto_explain.log_min_duration" low enough, the execution plans of
> all SQL statements calle from a function will be logged.
>
> Yours,
> Laurenz Albe

I did not know about this, it could be useful in future. Thanks.

Sadly, it does not solve our problem. When used on the INSERT INTO dummytable,
it produces:

2015-08-17 14:08:14 GMT LOG:  duration: 1.274 ms  plan:
        Query Text: INSERT INTO dummytable [...]
        Insert on dummytable  (cost=44.44..44.45 rows=1 width=0) (actual
time=2.956..2.956 rows=0 loops=1)
          InitPlan 1 (returns $0)
[...]
          ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual
time=0.013..0.013 rows=1 loops=1)

There is nothing in the log about calling trigger. I edited the trigger
function so it would use the slow select, and the output in the log was
exactly  the same (not counting different - longer - durations).

When I do EXPLAIN ANALYZE, at least I get some info about the trigger:

Insert on dummytable  (cost=44.44..44.45 rows=1 width=0) (actual
time=1.135..1.135 rows=0 loops=1)
   InitPlan 1 (returns $0)
[...]
   ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.018..0.018
rows=1 loops=1)
 Planning time: 0.111 ms
 Trigger trigger: time=1.113 calls=1
 Execution time: 1.244 ms


-- Zdeněk Bělehrádek


Re: How to EXPLAIN a trigger function

From
Zdeněk Bělehrádek
Date:
Dne Po 17. srpna 2015 13:25:25, Albe Laurenz napsal(a):
> Zdenek Belehrádek wrote:
>
> > We
> > would like to know if there is simple way to EXPLAIN the trigger function,
> > so we could optimize it.
>
>
> I believe that the auto_explain module could help you:
> http://www.postgresql.org/docs/current/static/auto-explain.html
>
> If you turn on "auto_explain.log_nested_statements" and set
> "auto_explain.log_min_duration" low enough, the execution plans of
> all SQL statements calle from a function will be logged.
>
> Yours,
> Laurenz Albe

Oh, sorry, I am an idiot. I totally missed the
auto_explain.log_nested_statements. With it set to true, I am getting the
trigger's EXPLAIN too.

Thank you very much!

--Zdeněk Bělehrádek.