Skip to content

Commit 9a4ec71

Browse files
authored
feat(sql): Speed up LatestForecast, enable pg_cron (#113)
1 parent e704a73 commit 9a4ec71

File tree

9 files changed

+54
-89
lines changed

9 files changed

+54
-89
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ gen.proto.python: ${PROTOC}
197197
.PHONY: run.db # Run an instance of Postgres with the required extensions
198198
run.db:
199199
docker build -f internal/server/postgres/infra/Containerfile internal/server/postgres/infra -t data-platform-pgdb:local
200-
docker run --rm -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p "5400:5432" data-platform-pgdb:local
200+
docker run --rm -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres -p "5400:5432" data-platform-pgdb:local postgres -c 'shared_preload_libraries=pg_cron' -c 'cron.database_name=postgres'
201201

202202
.PHONY: run.notebook # Run a python notebook to inspect the API
203203
run.notebook: gen.proto.python

internal/server/postgres/infra/Containerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ RUN apt-get update \
66
&& apt-get install -y --no-install-recommends \
77
postgresql-16-postgis-3 \
88
postgresql-16-postgis-3-scripts \
9+
&& apt-get install -y --no-install-recommends postgresql-16-cron \
910
&& rm -rf /var/lib/apt/lists/*
1011

11-
COPY init_postgis.sh /docker-entrypoint-initdb.d/10_init_postgis.sh
12-
COPY init_partman_bgw.sh /docker-entrypoint-initdb.d/99_init_partman_bgw.sh

internal/server/postgres/infra/init_partman_bgw.sh

Lines changed: 0 additions & 53 deletions
This file was deleted.

internal/server/postgres/infra/init_postgis.sh

Lines changed: 0 additions & 17 deletions
This file was deleted.

internal/server/postgres/package_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,13 @@ func setupTestMain(ctx context.Context, m *testing.M) (code int, err error) {
5858
"POSTGRES_PASSWORD": "postgres",
5959
"POSTGRES_DB": "postgres",
6060
},
61-
Cmd: []string{"postgres", "-c", "fsync=off"},
61+
Cmd: []string{
62+
"postgres",
63+
"-c",
64+
"fsync=off",
65+
"-c",
66+
"shared_preload_libraries=pg_cron",
67+
},
6268
ExposedPorts: []string{"5432/tcp"},
6369
WaitingFor: wait.ForAll(
6470
wait.ForLog(

internal/server/postgres/sql/migrations/00002_locations.sql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
* One geometry can have multiple sources, e.g. the UK nation geometry can have solar, wind, etc.
1717
*/
1818

19-
CREATE SCHEMA loc;
2019
CREATE EXTENSION IF NOT EXISTS btree_gist;
21-
CREATE EXTENSION IF NOT EXISTS postgis;
20+
CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA public;
21+
CREATE SCHEMA IF NOT EXISTS topology;
22+
CREATE EXTENSION IF NOT EXISTS postgis_topology WITH SCHEMA topology;
23+
24+
CREATE SCHEMA loc;
2225

2326
/*- Lookups -----------------------------------------------------------------------------------*/
2427

@@ -164,3 +167,6 @@ CREATE INDEX ON loc.sources_mv USING gist (sys_period);
164167

165168
-- +goose Down
166169
DROP SCHEMA loc CASCADE;
170+
DROP EXTENSION IF EXISTS postgis_topology;
171+
DROP EXTENSION IF EXISTS postgis;
172+
DROP EXTENSION IF EXISTS btree_gist;

internal/server/postgres/sql/migrations/00003_observations.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
* with these providers provide access to the data in order to test the accuracy of predictions.
99
*/
1010

11+
CREATE SCHEMA IF NOT EXISTS partman;
12+
CREATE EXTENSION IF NOT EXISTS pg_partman WITH SCHEMA partman;
13+
CREATE EXTENSION IF NOT EXISTS pg_cron;
14+
1115
CREATE SCHEMA obs;
1216

1317
/*- Tables ----------------------------------------------------------------------------------*/
@@ -83,6 +87,15 @@ SET
8387
infinite_time_partitions = TRUE
8488
WHERE parent_table = 'obs.observed_generation_values';
8589
SELECT partman.run_maintenance('obs.observed_generation_values');
90+
-- Schedule regular maintenance for the partitioned observed generation values table.
91+
SELECT cron.schedule('partman-maintenance', '@hourly', $$CALL partman.run_maintenance_proc()$$);
92+
SELECT cron.schedule('cron-details-cleanup', '0 12 * * *', $$DELETE FROM cron.job_run_details WHERE end_time < now() - interval '7 days'$$);
93+
8694

8795
-- +goose Down
96+
SELECT cron.unschedule('partman-maintenance');
8897
DROP SCHEMA obs CASCADE;
98+
99+
DROP EXTENSION IF EXISTS pg_cron CASCADE;
100+
DROP EXTENSION IF EXISTS pg_partman CASCADE;
101+
DROP SCHEMA IF EXISTS partman CASCADE;

internal/server/postgres/sql/migrations/00004_predictions.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ CREATE TABLE pred.forecasts (
125125
PRIMARY KEY (forecast_uuid),
126126
UNIQUE (geometry_uuid, source_type_id, forecaster_id, init_time_utc)
127127
);
128-
CREATE INDEX ON pred.forecasts USING GIST (target_period);
128+
CREATE INDEX idx_forecasts_filter ON pred.forecasts USING GIST (geometry_uuid, source_type_id, target_period);
129129

130130
/*
131131
* Table to store predicted generation values.
@@ -200,3 +200,4 @@ SELECT partman.run_maintenance('pred.predicted_generation_values');
200200

201201
-- +goose Down
202202
DROP SCHEMA pred CASCADE;
203+

internal/server/postgres/sql/queries/predictions.sql

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,23 +106,33 @@ INSERT INTO pred.predicted_generation_values (
106106
* and source type made by all forecasters. Only forecasts that are older than the pivot time
107107
* minus the specified horizon are considered.
108108
*/
109+
WITH latest_forecasts AS (
110+
SELECT DISTINCT ON (f.forecaster_id)
111+
f.forecast_uuid,
112+
f.init_time_utc,
113+
f.source_type_id,
114+
f.geometry_uuid,
115+
f.forecaster_id
116+
FROM pred.forecasts AS f
117+
WHERE f.geometry_uuid = $1
118+
AND f.source_type_id = $2
119+
AND f.init_time_utc
120+
<= sqlc.arg(pivot_timestamp)::TIMESTAMP - MAKE_INTERVAL(mins => sqlc.arg(horizon_mins)::INTEGER)
121+
AND f.target_period @> sqlc.arg(pivot_timestamp)::TIMESTAMP
122+
ORDER BY
123+
f.forecaster_id ASC,
124+
f.forecast_uuid DESC
125+
)
126+
-- Only join to forecaster table to sort by name once forecasts have been filtered
109127
SELECT DISTINCT ON (fr.forecaster_name)
110-
f.forecast_uuid,
111-
f.init_time_utc,
112-
f.source_type_id,
113-
f.geometry_uuid,
128+
lf.*,
114129
fr.forecaster_name,
115130
fr.forecaster_version,
116-
UUIDV7_EXTRACT_TIMESTAMP(f.forecast_uuid) AS created_at_utc
117-
FROM pred.forecasts AS f
131+
UUIDV7_EXTRACT_TIMESTAMP(lf.forecast_uuid) AS created_at_utc
132+
FROM latest_forecasts AS lf
118133
INNER JOIN pred.forecasters AS fr USING (forecaster_id)
119-
WHERE f.geometry_uuid = $1
120-
AND f.source_type_id = $2
121-
AND f.init_time_utc <= sqlc.arg(pivot_timestamp)::TIMESTAMP - MAKE_INTERVAL(mins => sqlc.arg(horizon_mins)::INTEGER)
122-
AND f.target_period @> sqlc.arg(pivot_timestamp)::TIMESTAMP
123134
ORDER BY
124-
fr.forecaster_name ASC,
125-
f.init_time_utc DESC;
135+
fr.forecaster_name ASC;
126136

127137
-- name: ListForecasts :many
128138
/* ListForecasts retrieves all the forecasts for a given location, source type, and forecaster

0 commit comments

Comments
 (0)