add batch remove batch split batch comment selection show hidden batches hide batch highlight batch
db<>fiddle
donate feedback about
By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
Help with an interesting Postgres question: Why isn't an Index Only Scan used on a partition accessed via the parent table?.
CREATE TABLE myTable (
datetime TEXT,
sys_id INT,
cputil REAL,
memfree REAL,
sessnum INT,
util_lag REAL, -- to be calculated AFTER INSERT via TRIGGER
mem_lag REAL, -- to be calculated AFTER INSERT via TRIGGER
util_diff REAL, -- to be calculated AFTER INSERT via TRIGGER
mem_diff REAL,/*a comma was missing here*/ -- to be calculated AFTER INSERT via TRIGGER
util_change TEXT -- to be calculated AFTER INSERT via TRIGGER
);
CREATE TABLE
ALTER TABLE myTable ALTER COLUMN datetime TYPE timestamptz
USING (datetime::timestamptz);
CREATE INDEX dtidx ON myTable (datetime)
--INCLUDE (cputil, memfree)
WITH (fillfactor=100);
--ALTER TABLE myTable CLUSTER ON dtidx;
ALTER TABLE
CREATE INDEX
vacuum analyze myTable;
VACUUM
CREATE OR REPLACE FUNCTION fn_calculate_columns_after_insert()--missing parentheses here
RETURNS TRIGGER LANGUAGE PLPGSQL AS $f$
BEGIN
SELECT cputil, memfree
INTO NEW.util_lag, NEW.mem_lag
FROM myTable
WHERE datetime < NEW.datetime
ORDER BY datetime DESC
LIMIT 1;

NEW.util_diff := NEW.cputil - NEW.util_lag;
NEW.mem_diff := NEW.memfree - NEW.mem_lag;
--the three cases explicitly say what you want and when
--ELSE no longer assumes the same case for 0 and null
--null is possible if there were any nulls involved earlier
IF NEW.util_diff > 0 THEN
NEW.util_change := 'Up';
ELSIF NEW.util_diff < 0 THEN
NEW.util_change := 'Down';
ELSIF NEW.util_diff = 0 THEN
NEW.util_change := '';
END IF;--this was missing
RETURN NEW;
END;--This semicolon is optional because it's immediately followed by closing dollar qoutes.
$f$;--This semicolon was missing. It is not optional, because it ends the whole `create function` statement

CREATE TRIGGER tr_fill_calculated_columns
BEFORE INSERT ON myTable
FOR EACH ROW
EXECUTE FUNCTION fn_calculate_columns_after_insert();
CREATE FUNCTION
CREATE TRIGGER
set datestyle=ISO, YMD;
insert into myTable(datetime,sys_id,cputil,memfree,sessnum)values
('2019/05/03 08:06:14',100,0.57,0.51,47)
,('2019/05/03 08:11:14',100,0.47,0.62,43)
,('2019/05/03 08:16:14',100,0.56,0.57,62) returning *;
SET
datetime sys_id cputil memfree sessnum util_lag mem_lag util_diff mem_diff util_change
2019-05-03 08:06:14+00 100 0.57 0.51 47 null null null null null
2019-05-03 08:11:14+00 100 0.47 0.62 43 0.57 0.51 -0.099999994 0.110000014 Down
2019-05-03 08:16:14+00 100 0.56 0.57 62 0.47 0.62 0.09 -0.050000012 Up
INSERT 0 3
select setseed(.42);

explain analyze verbose
insert into myTable(datetime,sys_id,cputil,memfree,sessnum)
select datetime,100 as sys_id,
round(random()::numeric,2) as cputil,
round(random()::numeric,2) as memfree,
100*random() as sessnum
from generate_series('2019/05/03 08:16:14'::timestamptz,
'2021/06/03 00:00:00', '5 minutes')_(datetime);
setseed
SELECT 1
QUERY PLAN
Insert on public.mytable (cost=0.00..37.50 rows=0 width=0) (actual time=7690.322..7690.324 rows=0 loops=1)
  -> Subquery Scan on "*SELECT*" (cost=0.00..37.50 rows=1000 width=72) (actual time=34.635..1340.655 rows=219357 loops=1)
        Output: "*SELECT*".datetime, "*SELECT*".sys_id, "*SELECT*".cputil, "*SELECT*".memfree, "*SELECT*".sessnum, NULL::real, NULL::real, NULL::real, NULL::real, NULL::text
        -> Function Scan on pg_catalog.generate_series _ (cost=0.00..30.00 rows=1000 width=84) (actual time=34.629..1021.677 rows=219357 loops=1)
              Output: _.datetime, 100, round((random())::numeric, 2), round((random())::numeric, 2), ('100'::double precision * random())
              Function Call: generate_series('2019-05-03 08:16:14+00'::timestamp with time zone, '2021-06-03 00:00:00+00'::timestamp with time zone, '00:05:00'::interval)
Planning Time: 0.067 ms
Trigger tr_fill_calculated_columns: time=5008.074 calls=219357
Execution Time: 7691.204 ms
EXPLAIN
explain analyze verbose
SELECT cputil, memfree
-- INTO NEW.util_lag, NEW.mem_lag
FROM myTable
WHERE datetime < '2021/09/03 00:00:00'
ORDER BY datetime DESC
LIMIT 1;
QUERY PLAN
Limit (cost=0.42..0.60 rows=1 width=16) (actual time=0.021..0.022 rows=1 loops=1)
  Output: cputil, memfree, datetime
  -> Index Scan Backward using dtidx on public.mytable (cost=0.42..9901.52 rows=55377 width=16) (actual time=0.021..0.021 rows=1 loops=1)
        Output: cputil, memfree, datetime
        Index Cond: (mytable.datetime < '2021-09-03 00:00:00+00'::timestamp with time zone)
Planning Time: 0.272 ms
Execution Time: 0.041 ms
EXPLAIN
explain analyze verbose
SELECT cputil, memfree
-- INTO NEW.util_lag, NEW.mem_lag
FROM myTable
--WHERE datetime < NEW.datetime
ORDER BY datetime DESC
LIMIT 1;
QUERY PLAN
Limit (cost=0.42..0.50 rows=1 width=16) (actual time=0.007..0.007 rows=1 loops=1)
  Output: cputil, memfree, datetime
  -> Index Scan Backward using dtidx on public.mytable (cost=0.42..12876.38 rows=166131 width=16) (actual time=0.006..0.006 rows=1 loops=1)
        Output: cputil, memfree, datetime
Planning Time: 0.029 ms
Execution Time: 0.015 ms
EXPLAIN