Files
HealthLog/prisma/migrations/0276_retention_purge_indexes/migration.sql
T

47 lines
2.4 KiB
SQL

-- v1.32.40 — indexes for the retention purges.
--
-- The nightly tombstone purge asks for `deleted_at IS NOT NULL AND deleted_at
-- < cutoff`, and the audit-log purge asks for `created_at < cutoff`. Neither
-- predicate had an index: every `deleted_at` index in the schema is PARTIAL on
-- `deleted_at IS NULL` (the live-rows predicate, the exact opposite of what a
-- purge needs), and every `audit_logs` index leads with `user_id` or `action`.
-- Both purges therefore planned a sequential scan and paid index maintenance
-- on every removed row. Each connection carries `statement_timeout=60000`
-- (`src/lib/db.ts`), so past a certain backlog the statement aborts, the
-- transaction rolls back, nothing is purged, and the next night runs the same
-- statement against the same rows. The purge that was meant to give deletion a
-- horizon could not close on the instances that needed it most.
--
-- The purges are batched as of the same release, so no single statement is on
-- the hook for a whole backlog; these indexes are what make each batch's
-- lookup cheap instead of a fresh sequential scan per batch.
--
-- The three tombstone indexes are PARTIAL on `deleted_at IS NOT NULL`, which
-- is the shape that matters here: on a healthy instance the index covers only
-- the tombstones, so it stays tiny and shrinks as the purge drains. Prisma
-- cannot express a partial predicate, so these stay raw-SQL-only — the same
-- convention as migrations 0087 / 0108 / 0243, noted at the model in
-- `schema.prisma`. `audit_logs(created_at)` is expressible and is declared on
-- the model.
--
-- Additive-only: every statement is `CREATE INDEX IF NOT EXISTS`, no table
-- rewrite, no data change. NON-CONCURRENT on purpose — Prisma Migrate wraps a
-- migration file in a transaction and `CREATE INDEX CONCURRENTLY` cannot run
-- in one; these build at boot, where docker-entrypoint runs `migrate deploy`
-- before the app serves traffic, so the build lock lands pre-traffic.
CREATE INDEX IF NOT EXISTS "measurements_tombstone_purge_idx"
ON "measurements" ("deleted_at")
WHERE "deleted_at" IS NOT NULL;
CREATE INDEX IF NOT EXISTS "mood_entries_tombstone_purge_idx"
ON "mood_entries" ("deleted_at")
WHERE "deleted_at" IS NOT NULL;
CREATE INDEX IF NOT EXISTS "medication_intake_events_tombstone_purge_idx"
ON "medication_intake_events" ("deleted_at")
WHERE "deleted_at" IS NOT NULL;
CREATE INDEX IF NOT EXISTS "audit_logs_created_at_idx"
ON "audit_logs" ("created_at");