Skip to content

Commit ce368dd

Browse files
authored
perf(database): index EnvironmentVariableValue.valueReferenceId so secret deletes stop seq-scanning (#4555)
## Why this change `EnvironmentVariableValue.valueReference` is an `onDelete: SetNull` foreign key. Deleting a `SecretReference` (the env var edit/delete path for secret values) fires the cascade `UPDATE ONLY "EnvironmentVariableValue" SET "valueReferenceId" = NULL WHERE $1 = "valueReferenceId"`. That cascade is scan-shaped: with no index on `valueReferenceId`, it reads the entire table to find the rows referencing the deleted secret. The parent `SecretReference` delete does almost no work itself; its latency is dominated by this cascade. ## Diagnosis `EnvironmentVariableValue` was indexed on `environmentId` and `(variableId, environmentId)`, but not on `valueReferenceId`. The SET NULL cascade therefore did a full sequential scan of the whole table. Two sibling SET NULL cascades on the same delete (`OrganizationIntegration.tokenReferenceId`, `User.mfaSecretReferenceId`) are index-backed and stay fast, which isolates the missing index as the cause. ## Change Add `@@index([valueReferenceId])` on `EnvironmentVariableValue`, created with `CREATE INDEX CONCURRENTLY IF NOT EXISTS` so `prisma migrate deploy` stays safe on a live table. ## Benchmark (local, seeded) Local Postgres seeded with 1,000,000 `EnvironmentVariableValue` rows, `EXPLAIN (ANALYZE, BUFFERS)` on the SET NULL cascade with zero matching rows (the worst case: reads the whole table, affects nothing): | | before | after | |---|---|---| | plan | Seq Scan (1M rows) | Bitmap Index Scan | | execution | 183 ms | 2.8 ms | In a variant where the secret matched several thousand rows, the parent `SecretReference` delete's `EnvironmentVariableValue_valueReferenceId_fkey` trigger dropped from 216 ms to 88 ms (the residual is the heap work of nulling those rows). ## Expected impact The cascade drops from a full-table sequential scan to a targeted index lookup. The win grows with the table, so the benefit is larger than the seeded numbers above. ## Risks - One extra btree to maintain on `EnvironmentVariableValue` writes; small, single-column, and it should be pre-created before the migration deploys (per the repo index rules). - No behavior change: same rows nulled, no ordering or result-set change, read paths untouched. Companion to the same fix on `ProjectAlert.channelId`.
1 parent 4c58091 commit ce368dd

3 files changed

Lines changed: 9 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
area: webapp
3+
type: improvement
4+
---
5+
6+
Deleting or editing a secret environment variable is now fast and no longer slows down as a project accumulates variables.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- CreateIndex
2+
CREATE INDEX CONCURRENTLY IF NOT EXISTS "EnvironmentVariableValue_valueReferenceId_idx" ON "public"."EnvironmentVariableValue"("valueReferenceId");

internal-packages/database/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,7 @@ model EnvironmentVariableValue {
20672067
20682068
@@unique([variableId, environmentId])
20692069
@@index([environmentId])
2070+
@@index([valueReferenceId])
20702071
}
20712072

20722073
model Checkpoint {

0 commit comments

Comments
 (0)