Skip to content

perf(database): index ProjectAlert.channelId so alert-channel deletes stop seq-scanning - #4554

Merged
ericallam merged 1 commit into
mainfrom
feature/tri-13095-index-projectalertchannelid-so-alert-channel-deletes-stop
Aug 10, 2026
Merged

perf(database): index ProjectAlert.channelId so alert-channel deletes stop seq-scanning#4554
ericallam merged 1 commit into
mainfrom
feature/tri-13095-index-projectalertchannelid-so-alert-channel-deletes-stop

Conversation

@ericallam

@ericallam ericallam commented Aug 10, 2026

Copy link
Copy Markdown
Member

Why this change

Deleting a ProjectAlertChannel fires the FK cascade DELETE FROM ONLY "ProjectAlert" WHERE $1 = "channelId". That cascade is scan-shaped: with no index on channelId, it reads the entire ProjectAlert table to find the few child rows belonging to the deleted channel. The parent DELETE ProjectAlertChannel does almost no work itself; its latency is dominated by this cascade. ProjectAlert is append-heavy and grows over time, so the scan cost only increases.

Diagnosis

ProjectAlert had no index on channelId (only pkey + a friendlyId unique). The cascade therefore did a full sequential scan of the whole table. The sibling ProjectAlertStorage cascade on the same delete is index-backed and stays fast, which isolates the missing index as the cause.

Change

Add @@index([channelId]) on ProjectAlert, 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 ProjectAlert rows across 50 channels (~20k rows per channel), EXPLAIN (ANALYZE, BUFFERS) on the cascade delete:

before after
plan Seq Scan (1M rows) Bitmap Index Scan
direct child delete 740 ms 22 ms
parent delete ProjectAlert_channelId_fkey trigger 77.7 ms 23.8 ms

Expected impact

The cascade drops from a full-table sequential scan to a targeted index lookup. The win grows with the table: the more rows in ProjectAlert, the more a scan costs and the more the index saves, so the benefit is larger than the seeded numbers above.

Risks

  • One extra btree to maintain on every ProjectAlert insert; acceptable for a single-column index on a high-insert table, and it should be pre-created before the migration deploys (per the repo index rules).
  • No behavior change: no rows orphaned, no ordering or result-set change, read paths untouched.

Follow-up

ProjectAlert's other cascade FK columns (projectId, environmentId, workerDeploymentId) are also unindexed, but their parents are soft-deleted rather than physically removed, so those cascades do not currently fire. Lower priority unless a hard-delete path is introduced.

@changeset-bot

changeset-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a059460

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds an index on ProjectAlert.channelId to the Prisma schema. Adds a concurrent, idempotent migration to create the database index. Documents faster alert-channel deletion as alert history grows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the problem, diagnosis, change, benchmark, impact, risks, and follow-up, but it omits the required issue, checklist, changelog, and screenshots sections. Add the template sections, including the issue reference, completed checklist, explicit testing steps, changelog entry, and screenshots or a statement that screenshots are not applicable.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary database performance change and its effect on ProjectAlertChannel deletes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tri-13095-index-projectalertchannelid-so-alert-channel-deletes-stop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]

This comment was marked as resolved.

@ericallam
ericallam marked this pull request as ready for review August 10, 2026 12:37

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@ericallam
ericallam merged commit 4c58091 into main Aug 10, 2026
44 checks passed
@ericallam
ericallam deleted the feature/tri-13095-index-projectalertchannelid-so-alert-channel-deletes-stop branch August 10, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants