Files
HealthLog/prisma/migrations/0243_perf_boot_discovery_partial_indexes/migration.sql
T
Marc-André Bombeck 656e96f72b chore(release): v1.28.46 — server performance on large instances
Deferred perf fixes from the campaign's verified perf-correctness audit,
correctness-first (each with an output-equivalence test):

- comprehensive-generate fan-out: replaced per-type 400d findMany+JS-average
  with DB prisma.aggregate(_avg) over the exact half-open windows the JS
  reducer used (current 30d, lastMonth (60d,30d], lastYear (395d,365d]), same
  rounding + null-on-empty, pLimit(4). SLEEP_DURATION stays on the raw path
  (per-night reconstruction dedup). Byte-equality test vs the old algorithm.
- boot-discovery: replaced Prisma in-memory distinct with DB SELECT DISTINCT
   in the 4 backfill discovery scans + migration 0243 (7 additive
  partial indexes matching each predicate). Integration test asserts identical
  discovered set against real Postgres.
- ChatBubble wrapped in React.memo with a comparator (onRegenerate compared by
  presence — the thread rebuilds it each render), so only the streaming bubble
  re-renders per token.
- doctor-report mood read narrowed to {score, tags} (the only fields the
  collector uses); the 730d main measurement read left as-is — a blind bound
  would corrupt clinical stats (documented deferred follow-up).

Migration 0243 additive-only.
2026-07-16 06:47:36 +02:00

55 lines
3.0 KiB
SQL

-- v1.28.46 perf (H4) — partial indexes for the boot-time converging-backfill
-- discovery scans. Each discovery now runs a DB-level `SELECT DISTINCT user_id`
-- over a growth table filtered by a "still-un-migrated" predicate; without an
-- index that is a full filtered-partition scan at worker boot (the boot-storm
-- class on a heavy tenant). Each index below is PARTIAL on exactly the
-- discovery predicate, so the scan is index-only and shrinks to nothing as the
-- one-time backfill converges (a migrated row drops out of the predicate).
--
-- 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 (docker-entrypoint runs `migrate deploy` BEFORE the
-- app serves traffic), so the brief build lock lands in the pre-traffic window.
-- Partial predicates match the write-side note convention (partial indexes are
-- raw-SQL-only here; Prisma cannot express a partial predicate — see the 0087 /
-- 0108 / 0183 precedents documented in schema.prisma).
-- note-encryption-backfill: measurements (densest table) + mood_entries.
CREATE INDEX IF NOT EXISTS "measurements_note_backfill_idx"
ON "measurements" ("user_id")
WHERE "notes" IS NOT NULL AND "notes_encrypted" IS NULL;
CREATE INDEX IF NOT EXISTS "mood_entries_note_backfill_idx"
ON "mood_entries" ("user_id")
WHERE "note" IS NOT NULL AND "note_encrypted" IS NULL;
-- med-notes-encryption-backfill: side-effects, inventory items, dose-changes.
-- Dose-changes carry no user_id; the discovery joins to medications on
-- medication_id, so the partial index leads with that join key.
CREATE INDEX IF NOT EXISTS "medication_side_effects_note_backfill_idx"
ON "medication_side_effects" ("user_id")
WHERE "notes" IS NOT NULL AND "notes_encrypted" IS NULL;
CREATE INDEX IF NOT EXISTS "medication_inventory_items_note_backfill_idx"
ON "medication_inventory_items" ("user_id")
WHERE "notes" IS NOT NULL AND "notes_encrypted" IS NULL;
CREATE INDEX IF NOT EXISTS "medication_dose_changes_note_backfill_idx"
ON "medication_dose_changes" ("medication_id")
WHERE "note" IS NOT NULL AND "note_encrypted" IS NULL;
-- lab-biomarker-backfill: unlinked live lab results.
CREATE INDEX IF NOT EXISTS "lab_results_biomarker_backfill_idx"
ON "lab_results" ("user_id")
WHERE "deleted_at" IS NULL AND "biomarker_id" IS NULL;
-- document-thumbnail-backfill: live thumbnailable documents. The thumbnail
-- absence lives on the `document_thumbnails` side table (a cross-table
-- anti-join, not indexable here); this partial index bounds the document-side
-- scan on `(user_id, mime_type)` for live rows, and the anti-join rides
-- `document_thumbnails.document_id` (already UNIQUE via the 1:1 relation).
CREATE INDEX IF NOT EXISTS "inbound_documents_thumbnail_backfill_idx"
ON "inbound_documents" ("user_id", "mime_type")
WHERE "deleted_at" IS NULL;