From b49fbc42655aa8a20a139695ca395ea0cb29ce70 Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Thu, 2 Jul 2026 16:24:57 +0000 Subject: [PATCH] Add index on plan_recommendations.recommendation_id to Drizzle schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan deletes cascade to recommendation rows, and each cascaded delete fires an FK check against plan_recommendations.recommendation_id. With ~26M rows and no index on that column the check seq-scans per row, making any plan deletion path time out. The index already exists on the live DB (created CONCURRENTLY on 2026-07-02 as idx_plan_recommendations_recommendation_id, 74s build); this brings the Drizzle schema in line so it stops drifting. No migration is included — generating/applying it is left as a human action, and it must reuse the existing index name (IF NOT EXISTS) so it no-ops against prod. Co-Authored-By: Claude Fable 5 --- src/app/db/schema/recommendations.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/db/schema/recommendations.ts b/src/app/db/schema/recommendations.ts index 0c74a584..af7acf0e 100644 --- a/src/app/db/schema/recommendations.ts +++ b/src/app/db/schema/recommendations.ts @@ -263,6 +263,13 @@ export const planRecommendations = pgTable( table.planId, table.recommendationId, ), + // Supports the FK check fired when `recommendation` rows are deleted + // (cascaded from plan deletes); without it each delete seq-scans this + // ~26M-row table. Already created on the live DB (CONCURRENTLY, + // 2026-07-02) — the migration must match the existing index name. + index("idx_plan_recommendations_recommendation_id").on( + table.recommendationId, + ), ], );