Re: Why adding BEFORE TRIGGER affect client CPU?

From: Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com>
To: George Woodring <george(dot)woodring(at)iglass(dot)net>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-general <pgsql-general(at)postgresql(dot)org>
Subject: Re: Why adding BEFORE TRIGGER affect client CPU?
Date: 2019-01-18 22:18:02
Message-ID: a05fef20-7191-9062-c8a4-4dcbeb5ad3ae@aklaver.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On 1/18/19 12:21 PM, George Woodring wrote:
> Adrian Klaver <adrian(dot)klaver(at)aklaver(dot)com
> <mailto:adrian(dot)klaver(at)aklaver(dot)com>> writes:
> > What is the client server and what is it doing?
>
> Our client creates a temp table
> CREATE TEMP TABLE myraw(LIKE raw INCLUDING DEFAULTS)
> We load data with a copy
> COPY myraw (transferid, pollgrpid, date, data, rrdtypeid, error ) FROM
> STDIN WITH DELIMITER '|'
> We do some checking on the data in the temp table
> SELECT rawdate, raw_maint(rawdate) AS checked FROM (SELECT
> date_trunc('minute', date) AS rawdate FROM myraw GROUP BY rawdate) AS foo;
> Then we save the data into the permanent location
> SELECT transferid, pollgrpid, process_lastpoll(ROW(myraw.*)::raw) AS
> processed FROM myraw ORDER BY transferid
>
> Our change was in the process_lastpoll() function.  We went from
>       IF cntr THEN
>          oval := calc_last_cntr(ptype, pgid, ds, pdate, data);
>       ELSE
>          oval := data;
>       END IF;
>
>       -- Insert data into table
>       -- RAISE DEBUG 'Process: dsnum=%, polltype=%, cntr?=%, pdate=%,
> data=%, oval=%', dsnum, ptype, cntr, pdate, data, oval;
>       UPDATE lastpoll SET polltype=ptype, timeslot=ts, lasttime=pdate,
> lastval=data, outval=oval, error=err WHERE pollgrpid=pgid AND dsnum=ds;
>       IF found THEN
>          RETURN true;
>       END IF;
>       BEGIN
>          INSERT INTO lastpoll (timeslot, pollgrpid, dsnum, polltype,
> lasttime, lastval, outval, error) VALUES (ts, pgid, ds, ptype, pdate,
> data, oval, err);
>          RETURN true;
>       EXCEPTION WHEN unique_violation THEN
>          -- Don't do anything
>       END;
> to this
>       IF NOT cntr THEN
>          oval := data;
>       END IF;
>
>       -- Insert data into table
>       -- RAISE DEBUG 'Process: dsnum=%, polltype=%, cntr?=%, pdate=%,
> data=%, oval=%', dsnum, ptype, cntr, pdate, data, oval;
>       UPDATE lastpoll SET polltype=ptype, timeslot=ts, lasttime=pdate,
> lastval=data, outval=oval, error=err WHERE pollgrpid=pgid AND dsnum=ds;
>       IF found THEN
>          RETURN true;
>       END IF;
>       BEGIN
>          INSERT INTO lastpoll (timeslot, pollgrpid, dsnum, polltype,
> lasttime, lastval, outval, error) VALUES (ts, pgid, ds, ptype, pdate,
> data, oval, err);
>          RETURN true;
>       EXCEPTION WHEN unique_violation THEN
>          -- Don't do anything
>       END;
>
> The calc_last_cntr() was replaced with the trigger.
> from:
> CREATE OR REPLACE FUNCTION calc_last_cntr(ptype text, pgid int4, ds
> int4, pdate timestamp with time zone, data double precision) RETURNS
> double precision AS $$
>    DECLARE
>       mcurr RECORD;
>       res double precision;
>       dwindow int4;
>    BEGIN
>       SELECT lasttime, lastval INTO mcurr FROM lastpoll WHERE
> pollgrpid=pgid AND dsnum=ds;
>       IF mcurr IS NULL THEN
>          -- RAISE DEBUG 'No previous data found for pgid=%', pgid;
>          return NULL;
>       END IF;
>
>       -- Calculate the counter rate
>       -- Check for div by 0
>       dwindow := EXTRACT(EPOCH FROM (pdate - mcurr.lasttime));
>       IF dwindow = 0 THEN
>          RAISE WARNING '(%) Time difference is zero (% - %)',
> current_database(), pdate, mcurr.lasttime;
>          return NULL;
>       END IF;
>
>       res := (data - mcurr.lastval)/dwindow;
>       IF res < 0 THEN
>          -- RAISE DEBUG 'Counter loop for pgid=%', pgid;
>          return data/dwindow;
>       END IF;
>
>       return res;
>    END;
> $$ LANGUAGE plpgsql;
>
> to:
> CREATE OR REPLACE FUNCTION cntr_lastpoll() RETURNS trigger AS $$
>    DECLARE
>       dwindow int4;
>    BEGIN
>       -- Log new value into history if has a date
>       IF NEW.outval IS NULL THEN
>          -- Calculate counter value for this DS.
>          dwindow := EXTRACT(EPOCH FROM (NEW.lasttime - OLD.lasttime));
>          IF dwindow = 0 THEN
>             RAISE WARNING '(%) Time difference is zero (% - %)',
> current_database(), NEW.lasttime, OLD.lasttime;
>             return NEW;
>          END IF;
>
>          NEW.outval := (NEW.lastval - OLD.lastval)/dwindow;
>          IF NEW.outval < 0 THEN
>             NEW.outval := NEW.lastval/dwindow;
>          END IF;
>
>       END IF;
>       RETURN NEW;
>    END;
> $$ LANGUAGE plpgsql;
>
> -- Create Trigger to calculate counter values if needed.
> CREATE TRIGGER lastpoll_counter BEFORE UPDATE ON lastpoll
>    FOR EACH ROW EXECUTE PROCEDURE cntr_lastpoll();
>
> On Fri, Jan 18, 2019 at 2:01 PM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us
> <mailto:tgl(at)sss(dot)pgh(dot)pa(dot)us>> wrote:
>
>  what uses that value client-side, exactly?
>

Not claiming to understand all that is going on above.

What I think I see:

1) New process_lastpoll() has:
UPDATE lastpoll SET polltype=ptype, timeslot=ts, lasttime=pdate,
lastval=data, outval=oval, error=err WHERE pollgrpid=pgid AND dsnum=ds;

2) calc_last_cntr() is now function for trigger:
CREATE TRIGGER lastpoll_counter BEFORE UPDATE ON lastpoll
FOR EACH ROW EXECUTE PROCEDURE cntr_lastpoll();

Seems to me you are double clutching on the outval value. You UPDATE it
in 1) then recalculate it again in 2).

As said earlier I do not fully understand what is going on, still seems
to me process_lastpoll() could go away and its code moved into
calc_last_cntr().

>
> The outval number is later read looking for values outside of a
> thresholds.  I did not think about it affecting selects later in the
> code.  All in all everything worked fine, but since the client box is an
> AWS EC2 instance, it started eating all of our CPU credits.
>
> image.png
>
>
> iGLASS Networks
> www.iglass.net <http://www.iglass.net>
>
>
>
>

--
Adrian Klaver
adrian(dot)klaver(at)aklaver(dot)com

In response to

Browse pgsql-general by date

  From Date Subject
Next Message bhargav kamineni 2019-01-19 10:38:23 Capacity Planning
Previous Message Abel Normand 2019-01-18 20:41:00 pgint.l -- PostgreSQL interface for PicoLisp