Thread: Trigger performance

Trigger performance

From
pginfo
Date:
Hi,

I need to speed up the triggers that we are using and I began to make
some tests to compare the "C" and pgSQL trigger performance.

I try to write two identical test triggers (sorry I do not know very
good the pgsql C interface and I got one of examples and werite it) and
attached it on insert of my test table.

After it I try to insert in thi stable ~ 160 K rows and compared the
speeds.

I was supprised that the pgsql trigger take ~8 sec. to insert this rows
and the "C" trigger take ~ 17 sec.

This are my triggers:
CREATE OR REPLACE FUNCTION trig1_t()
  RETURNS trigger AS
'
DECLARE

my_rec RECORD;

BEGIN

select into my_rec count(*) from ttest;

RETURN NEW;
END;
'
  LANGUAGE 'plpgsql' VOLATILE;

and this writen in "C":

#include "postgres.h"
 #include "executor/spi.h"       /* this is what you need to work with
SPI */
 #include "commands/trigger.h"   /* ... and triggers */

 extern Datum trigf(PG_FUNCTION_ARGS);

 PG_FUNCTION_INFO_V1(trigf);

 Datum
 trigf(PG_FUNCTION_ARGS)
 {
     TriggerData *trigdata = (TriggerData *) fcinfo->context;
     TupleDesc   tupdesc;
     HeapTuple   rettuple;
     char       *when;
     bool        checknull = false;
     bool        isnull;
     int         ret, i;

     /* make sure it's called as a trigger at all */
     if (!CALLED_AS_TRIGGER(fcinfo))
         elog(ERROR, "trigf: not called by trigger manager");

     /* tuple to return to executor */
     if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
         rettuple = trigdata->tg_newtuple;
     else
         rettuple = trigdata->tg_trigtuple;

     /* check for null values */
     if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
         && TRIGGER_FIRED_BEFORE(trigdata->tg_event))
         checknull = true;

     if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
         when = "before";
     else
         when = "after ";

     tupdesc = trigdata->tg_relation->rd_att;

     /* connect to SPI manager */
     if ((ret = SPI_connect()) < 0)
         elog(INFO, "trigf (fired %s): SPI_connect returned %d", when,
ret);

     /* get number of rows in table */
     ret = SPI_exec("SELECT count(*) FROM ttest", 0);

     if (ret < 0)
         elog(NOTICE, "trigf (fired %s): SPI_exec returned %d", when,
ret);


     SPI_finish();

     if (checknull)
     {
         SPI_getbinval(rettuple, tupdesc, 1, &isnull);
         if (isnull)
             rettuple = NULL;
     }

     return PointerGetDatum(rettuple);
 }



My question:
Can I do the "C" trigger to be faster that the pgSQL?

regards,
ivan.



Re: Trigger performance

From
Tom Lane
Date:
pginfo <pginfo@t1.unisoftbg.com> writes:
> I was supprised that the pgsql trigger take ~8 sec. to insert this rows
> and the "C" trigger take ~ 17 sec.

The reason is that plpgsql caches the plan for the invoked SELECT,
whereas the way you coded the C function, it's re-planning that SELECT
on every call.

            regards, tom lane

Re: Trigger performance

From
pginfo
Date:
Hi,

thanks for the answer.
It is very interest, because I readet many times that if I write the trigger
in "C" it will work faster.
In wich case will this trigger work faster if write it in "C"?
In all my triggres I have "select ...." or "insert into mytable select ..."
or "update mytable set ...where...".
I need this info because I have a table with ~1.5 M rows and if I start to
update 300 K from this rows it takes ~ 2h.
If I remove the trigger for this table all the time is ~ 1 min.

regards,
ivan.

Tom Lane wrote:

> pginfo <pginfo@t1.unisoftbg.com> writes:
> > I was supprised that the pgsql trigger take ~8 sec. to insert this rows
> > and the "C" trigger take ~ 17 sec.
>
> The reason is that plpgsql caches the plan for the invoked SELECT,
> whereas the way you coded the C function, it's re-planning that SELECT
> on every call.
>
>                         regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)




Re: Trigger performance

From
Tom Lane
Date:
pginfo <pginfo@t1.unisoftbg.com> writes:
> In wich case will this trigger work faster if write it in "C"?

Given that the dominant part of the time will be spent down inside SPI
in either case, I doubt you will be able to see much difference.  You
need to think about how to optimize the invoked query, not waste your
time recoding the wrapper around it.

            regards, tom lane

Re: Trigger performance

From
pginfo
Date:
Ok, thanks.
I will do it.

regards,
ivan.

Tom Lane wrote:

> pginfo <pginfo@t1.unisoftbg.com> writes:
> > In wich case will this trigger work faster if write it in "C"?
>
> Given that the dominant part of the time will be spent down inside SPI
> in either case, I doubt you will be able to see much difference.  You
> need to think about how to optimize the invoked query, not waste your
> time recoding the wrapper around it.
>
>                         regards, tom lane




Re: Trigger performance

From
Pavel Stehule
Date:
Hello

try prepared statements, PQexecPrepared
http://developer.postgresql.org/docs/postgres/libpq-exec.html

Regards
Pavel Stehule

On Thu, 22 Jan 2004, pginfo wrote:

> Hi,
>
> thanks for the answer.
> It is very interest, because I readet many times that if I write the trigger
> in "C" it will work faster.
> In wich case will this trigger work faster if write it in "C"?
> In all my triggres I have "select ...." or "insert into mytable select ..."
> or "update mytable set ...where...".
> I need this info because I have a table with ~1.5 M rows and if I start to
> update 300 K from this rows it takes ~ 2h.
> If I remove the trigger for this table all the time is ~ 1 min.
>
> regards,
> ivan.
>
> Tom Lane wrote:
>
> > pginfo <pginfo@t1.unisoftbg.com> writes:
> > > I was supprised that the pgsql trigger take ~8 sec. to insert this rows
> > > and the "C" trigger take ~ 17 sec.
> >
> > The reason is that plpgsql caches the plan for the invoked SELECT,
> > whereas the way you coded the C function, it's re-planning that SELECT
> > on every call.
> >
> >                         regards, tom lane
> >
> > ---------------------------(end of broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)
>
>
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: the planner will ignore your desire to choose an index scan if your
>       joining column's datatypes do not match
>