fix(db): index large-value workflow_id FKs so workflow deletes don't seq-scan (#6136)

This commit is contained in:
Theodore Li
2026-07-31 16:48:52 -07:00
committed by GitHub
parent b77b9ee491
commit 4ef7bbad53
4 changed files with 18344 additions and 0 deletions
@@ -0,0 +1,14 @@
-- Both tables carry `workflow_id ... ON DELETE SET NULL` (migration 0212) with no index leading
-- on that column. Postgres implements SET NULL as an AFTER ROW referential trigger running
-- `UPDATE ... SET workflow_id = NULL WHERE workflow_id = $1` once per deleted parent row, so
-- every `DELETE FROM workflow` sequentially scans both tables per workflow — enough to blow the
-- statement timeout once the soft-delete retention job starts hard-deleting archived workflows.
-- Both indexes exist to make that trigger index-driven.
--
-- Replay-safety: this file is only CONCURRENTLY index builds below an embedded COMMIT, so a
-- failure replays the whole file — both statements are idempotent.
COMMIT;--> statement-breakpoint
SET lock_timeout = 0;--> statement-breakpoint
CREATE INDEX CONCURRENTLY IF NOT EXISTS "execution_large_value_references_workflow_id_idx" ON "execution_large_value_references" USING btree ("workflow_id");--> statement-breakpoint
CREATE INDEX CONCURRENTLY IF NOT EXISTS "execution_large_values_workflow_id_idx" ON "execution_large_values" USING btree ("workflow_id");--> statement-breakpoint
SET lock_timeout = '5s';
File diff suppressed because it is too large Load Diff
@@ -1940,6 +1940,13 @@
"when": 1785358812851,
"tag": "0277_workspace_sandboxes",
"breakpoints": true
},
{
"idx": 278,
"version": "7",
"when": 1785536864363,
"tag": "0278_charming_imperial_guard",
"breakpoints": true
}
]
}
+8
View File
@@ -501,6 +501,12 @@ export const executionLargeValues = pgTable(
tombstoneCleanupIdx: index('execution_large_values_tombstone_cleanup_idx')
.on(table.workspaceId, table.deletedAt, table.key)
.where(sql`${table.deletedAt} IS NOT NULL`),
/**
* Backs the `ON DELETE SET NULL` referential trigger, which runs
* `UPDATE ... WHERE workflow_id = $1` once per deleted workflow row and
* would otherwise sequentially scan this table each time.
*/
workflowIdIdx: index('execution_large_values_workflow_id_idx').on(table.workflowId),
})
)
@@ -521,6 +527,8 @@ export const executionLargeValueReferences = pgTable(
workspaceExecutionSourceIdx: index(
'execution_large_value_references_workspace_execution_source_idx'
).on(table.workspaceId, table.executionId, table.source),
/** Backs the `ON DELETE SET NULL` referential trigger — see `executionLargeValues`. */
workflowIdIdx: index('execution_large_value_references_workflow_id_idx').on(table.workflowId),
})
)