Commit 4658cd0
authored
perf(database): index WorkerDeployment on (environmentId, status, id) for the deployments list (#4591)
## What
Adds a composite index `@@index([environmentId, status, id])` to
`WorkerDeployment`.
The public deployments list (`GET /api/v1/deployments`) filters by
`status` and paginates by `id` descending. The existing indexes cover
`(environmentId, createdAt)` and the PK, but nothing covers `status`. So
for a status filter Postgres walks back through the environment's
deployments discarding non-matching statuses, reading roughly 350 rows
for every 1 returned (p99 ~1.1s on the busiest environments). The new
index makes the status filter index-satisfied and lets `id` serve both
the cursor range and the `ORDER BY id DESC`, bounding the read to a
single page.
Full composite (not partial) because callers filter by arbitrary status
values with no single dominant one.
## Query
```sql
SELECT ... FROM "WorkerDeployment"
WHERE "environmentId" = $1 AND "status" = $2 [AND "id" < $3]
ORDER BY "id" DESC LIMIT $4;
```
Source: `apps/webapp/app/routes/api.v1.deployments.ts`.
## Evidence
Reproduced on an isolated stack: one environment seeded with 7,000
deployments, the filtered status appearing 1 in 333 rows.
Before (no index):
```
Seq Scan on "WorkerDeployment" (rows=21)
Rows Removed by Filter: 6979
Buffers: shared hit=206
Execution Time: 2.9 ms (+ a sort for id desc)
```
After (with the index):
```
Index Scan Backward using "WorkerDeployment_environmentId_status_id_idx"
Index Cond: (environmentId = $1 AND status = $2)
Buffers: shared hit=23
Execution Time: 0.43 ms
```
Rows-removed-by-filter drops to 0; buffers 206 -> 23. The cursor
(mid-pagination) variant uses the same index with all three predicates
as the index condition. A dense/common status keeps the cheap PK
backward scan (already fine); the index targets exactly the rare-status
paths that were amplified.
End-to-end against the running webapp API: `?status=FAILED` returns the
correct newest-first page and paginates correctly across pages, and the
emitted SQL matches the query above.
## Rollout
- Index only, `CREATE INDEX CONCURRENTLY IF NOT EXISTS` in its own
migration file. Online-safe under write load.
- Pre-apply the index in production before the migration deploys, per
repo convention (the migration is then a no-op).
- Rollback: drop the index. No data migration.
refs TRI-131711 parent 7b7d489 commit 4658cd0
3 files changed
Lines changed: 8 additions & 0 deletions
File tree
- .server-changes
- internal-packages/database/prisma
- migrations/20260812130000_add_worker_deployment_environment_id_status_id_index
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2214 | 2214 | | |
2215 | 2215 | | |
2216 | 2216 | | |
| 2217 | + | |
2217 | 2218 | | |
2218 | 2219 | | |
2219 | 2220 | | |
| |||
0 commit comments