Question Details

No question body available.

Tags

sql postgresql window-functions

Answers (1)

July 15, 2026 Score: 2 Rep: 304 Quality: Low Completeness: 80%

Execution Time: 18167.869 ms is expected for this shape because the query is calculating two ordered window aggregates for all 16672172 rows. An index can reduce some sorting, but each request still recomputes every historical cumulative value and every historical average.

For a response-time query, store the intermediate result you reuse: cumulative volume per symbolid, day, and minute-of-day. Then the RVOL query reads that summary instead of running the nested windows over coreprice each time.

Assuming timestamp is Unix seconds and UTC day/minute buckets are acceptable:

CREATE TABLE corepricedayminute (
    symbolid bigint NOT NULL,
    dayno int NOT NULL,
    minuteofday int NOT NULL,
    cumulativevolume double precision NOT NULL,
    PRIMARY KEY (symbolid, dayno, minuteofday)
);

CREATE INDEX corepricedayminutervolidx ON corepricedayminute (symbolid, minuteofday, dayno) INCLUDE (cumulativevolume);

Refresh only the day that is still changing:

WITH todays AS (
    SELECT
        symbolid,
        ("timestamp" / 86400)::int AS dayno,
        (("timestamp" % 86400) / 60)::int AS minuteofday,
        sum(volume) OVER (
            PARTITION BY symbolid, ("timestamp" / 86400)
            ORDER BY "timestamp"
        ) AS cumulativevolume
    FROM coreprice
    WHERE "timestamp" >= :todaystart
      AND "timestamp" <  :tomorrowstart
)
INSERT INTO corepricedayminute AS d
    (symbolid, dayno, minuteofday, cumulativevolume)
SELECT symbolid, dayno, minuteofday, cumulativevolume
FROM todays
ON CONFLICT (symbolid, dayno, minuteofday)
DO UPDATE SET cumulativevolume = EXCLUDED.cumulativevolume;

Then RVOL is a grouped lookup against prior days:

SELECT
    c.symbolid,
    c.minuteofday,
    c.cumulativevolume / avg(h.cumulativevolume) AS relativevolume
FROM corepricedayminute c
JOIN corepricedayminute h
  ON h.symbolid = c.symbolid
 AND h.minuteofday = c.minuteofday
 AND h.dayno < c.dayno
WHERE c.dayno = :todaydayno
GROUP BY c.symbolid, c.minuteofday, c.cumulativevolume;

A plain PostgreSQL materialized view is a poor fit for refreshing this whole result every minute, because REFRESH MATERIALIZED VIEW completely replaces the contents of the materialized view. Use a table like the above when only the latest day changes; use a materialized view only for a batch result that can be rebuilt on that schedule.