obmp-docker/postgres/scripts/006_obmp_matviews.sql
sam cc0d20bf9e Back AS Relationship Map with a materialized view
The AS map previously exploded ~4.4M base_attrs AS_PATH rows live,
three times per load (one per panel), ~1.8s each — slow enough that
navigating away cancelled the queries mid-flight.

Add mv_as_adjacency: undirected consecutive-AS pairs with occurrence
counts over the full RIB (17k rows), refreshed hourly by pg_cron via
REFRESH ... CONCURRENTLY. The dashboard panels now read the view in
~1ms. Min-occurrence options rescaled for full-RIB counts
(2000/5000/10000/50000, default 2000 -> ~63-node graph).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 07:04:38 -07:00

27 lines
1.3 KiB
SQL

-- OBMP analytics materialized views
--
-- Applied to the live database and version-controlled here for reproducibility.
-- Safe to run against an empty database at init time: the view is created empty
-- and the pg_cron job below populates/refreshes it hourly.
-- AS adjacency: every undirected pair of consecutive ASes in an observed AS_PATH,
-- with an occurrence count. Backs the AS Relationship Map dashboard so its panels
-- read a 17k-row view instead of exploding ~4.4M base_attrs rows live.
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_as_adjacency AS
SELECT LEAST(a.asn, b.asn) AS asn_a,
GREATEST(a.asn, b.asn) AS asn_b,
COUNT(*) AS occ
FROM base_attrs ba
CROSS JOIN LATERAL unnest(ba.as_path) WITH ORDINALITY a(asn, ord)
JOIN LATERAL unnest(ba.as_path) WITH ORDINALITY b(asn, ord) ON b.ord = a.ord + 1
WHERE ba.as_path_count >= 2 AND a.asn <> b.asn
GROUP BY 1, 2;
-- Unique index required for REFRESH ... CONCURRENTLY (no read lock during refresh).
CREATE UNIQUE INDEX IF NOT EXISTS mv_as_adjacency_pair_idx ON mv_as_adjacency (asn_a, asn_b);
CREATE INDEX IF NOT EXISTS mv_as_adjacency_occ_idx ON mv_as_adjacency (occ DESC);
-- Refresh hourly at minute 23.
SELECT cron.schedule('refresh-mv-as-adjacency', '23 * * * *',
'REFRESH MATERIALIZED VIEW CONCURRENTLY mv_as_adjacency');