mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
131 lines
5.6 KiB
SQL
131 lines
5.6 KiB
SQL
-- 01_schema_setup.sql
|
|
-- Creates the demo schema, legacy table, OLTP workload table,
|
|
-- and all monitoring views for the CI migration danger demo.
|
|
--
|
|
-- Run as superuser (postgres) against knoe-db.
|
|
-- Safe to re-run: all objects use IF NOT EXISTS / CREATE OR REPLACE.
|
|
|
|
CREATE SCHEMA IF NOT EXISTS demo;
|
|
|
|
-- ── Legacy table (source of the backfill) ────────────────────────────────────
|
|
-- Represents the old non-partitioned ci_job_artifacts table on a 10 TB GitLab
|
|
-- DB. In our scaled demo we'll fill this with ~5 million rows (~1 GB).
|
|
CREATE TABLE IF NOT EXISTS demo.ci_job_artifacts_legacy (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
job_id BIGINT NOT NULL,
|
|
project_id BIGINT NOT NULL,
|
|
file_type SMALLINT NOT NULL DEFAULT 0,
|
|
size_bytes BIGINT,
|
|
file_store SMALLINT NOT NULL DEFAULT 1,
|
|
checksum TEXT,
|
|
created_at TIMESTAMP NOT NULL,
|
|
expire_at TIMESTAMP,
|
|
locked BOOLEAN DEFAULT FALSE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_legacy_created_at
|
|
ON demo.ci_job_artifacts_legacy (created_at);
|
|
|
|
-- ── OLTP workload table (concurrent traffic during migration) ─────────────────
|
|
-- Simulates background CI pipeline activity during the migration window.
|
|
-- UPDATEs to this table generate dead tuples that autovacuum must clean.
|
|
-- When a long-running migration transaction holds an old snapshot, autovacuum
|
|
-- is blocked and dead tuples pile up — this is the MVCC bloat we'll observe.
|
|
CREATE TABLE IF NOT EXISTS demo.ci_build_status (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
job_id BIGINT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ── Monitoring views ──────────────────────────────────────────────────────────
|
|
|
|
CREATE OR REPLACE VIEW demo.mvcc_bloat_monitor AS
|
|
SELECT
|
|
relname AS table_name,
|
|
n_live_tup AS live_rows,
|
|
n_dead_tup AS dead_rows,
|
|
ROUND(n_dead_tup::NUMERIC / NULLIF(n_live_tup, 0) * 100, 2) AS dead_pct,
|
|
last_autovacuum,
|
|
last_autoanalyze,
|
|
pg_size_pretty(pg_total_relation_size('demo.' || relname)) AS total_size,
|
|
pg_size_pretty(pg_relation_size('demo.' || relname)) AS table_size
|
|
FROM pg_stat_user_tables
|
|
WHERE schemaname = 'demo'
|
|
ORDER BY n_dead_tup DESC;
|
|
|
|
-- Shows any transaction open longer than 5 seconds — the migration blocker.
|
|
CREATE OR REPLACE VIEW demo.long_running_tx AS
|
|
SELECT
|
|
pid,
|
|
now() - xact_start AS tx_duration,
|
|
now() - query_start AS query_duration,
|
|
state,
|
|
wait_event_type,
|
|
wait_event,
|
|
left(query, 200) AS query_snippet,
|
|
backend_type,
|
|
application_name
|
|
FROM pg_stat_activity
|
|
WHERE xact_start IS NOT NULL
|
|
AND now() - xact_start > INTERVAL '5 seconds'
|
|
AND pid <> pg_backend_pid()
|
|
ORDER BY tx_duration DESC;
|
|
|
|
-- WAL generation tracker — shows how fast WAL is growing.
|
|
-- Run before and after to calculate the delta.
|
|
CREATE OR REPLACE VIEW demo.wal_progress AS
|
|
SELECT
|
|
pg_current_wal_lsn() AS current_lsn,
|
|
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0'::pg_lsn)) AS total_wal,
|
|
(SELECT count(*) FROM pg_ls_waldir()) AS wal_segment_count,
|
|
pg_size_pretty((SELECT sum(size) FROM pg_ls_waldir())) AS wal_dir_size;
|
|
|
|
-- Lock wait graph — shows who is blocking whom.
|
|
CREATE OR REPLACE VIEW demo.lock_waits AS
|
|
SELECT
|
|
blocked_a.pid AS blocked_pid,
|
|
blocking_a.pid AS blocking_pid,
|
|
now() - blocked_a.query_start AS wait_duration,
|
|
left(blocked_a.query, 120) AS blocked_query,
|
|
left(blocking_a.query, 120) AS blocking_query,
|
|
blocked_l.locktype,
|
|
blocked_l.relation::regclass AS locked_relation
|
|
FROM pg_catalog.pg_locks blocked_l
|
|
JOIN pg_catalog.pg_locks blocking_l
|
|
ON blocking_l.locktype = blocked_l.locktype
|
|
AND blocking_l.relation = blocked_l.relation
|
|
AND blocking_l.granted
|
|
AND NOT blocked_l.granted
|
|
JOIN pg_stat_activity blocked_a ON blocked_a.pid = blocked_l.pid
|
|
JOIN pg_stat_activity blocking_a ON blocking_a.pid = blocking_l.pid
|
|
ORDER BY wait_duration DESC;
|
|
|
|
-- Autovacuum activity — shows if autovacuum is currently running or stuck.
|
|
CREATE OR REPLACE VIEW demo.autovacuum_status AS
|
|
SELECT
|
|
pid,
|
|
now() - xact_start AS running_for,
|
|
query AS vacuum_query,
|
|
wait_event_type,
|
|
wait_event
|
|
FROM pg_stat_activity
|
|
WHERE query LIKE 'autovacuum:%'
|
|
ORDER BY xact_start;
|
|
|
|
-- Oldest transaction horizon — the horizon that blocks dead tuple cleanup.
|
|
-- When this is far in the past and dead tuples are climbing, we have MVCC bloat.
|
|
CREATE OR REPLACE VIEW demo.xmin_horizon AS
|
|
SELECT
|
|
pid,
|
|
backend_xmin AS xmin,
|
|
age(backend_xmin) AS xmin_age,
|
|
now() - xact_start AS tx_age,
|
|
state,
|
|
left(query, 120) AS query_snippet
|
|
FROM pg_stat_activity
|
|
WHERE backend_xmin IS NOT NULL
|
|
ORDER BY age(backend_xmin) DESC;
|
|
|
|
\echo 'Schema and views created. Run 02_generate_data.sql next.'
|