perf(audit-logs): index organization-level rows and read them as two keyset parts
Merged
WA
1d ago+31598+31598+01234567890123456789012345678901234567890123456789-19-19-01234567890123456789
Summary
Fixes a regression from #9419 in the organization audit-log listing.
- #9419 reads a page's ids as one keyset scan per org workspace plus one organization-level branch (
workspace_id IS NULLand the org named in metadata or as the resource). No index served that branch in order, so unless the organization had a page of org-level rows near the top, every listing walked every workspace-less audit row in the table, scattered across the heap. Listings got slower and long reads on the replica began hitting recovery-conflict cancellations - Migration 0444 adds
audit_log_org_level_created_at_id_idx, a partial index on(metadata->>'organizationId', date_trunc('milliseconds', created_at), id) WHERE workspace_id IS NULL AND metadata->>'organizationId' IS NOT NULL. It's built concurrently with the replay-safe invalid-index handling from 0442, and it only holds workspace-less rows that name an organization - The org-level branch is split into two disjoint keyset parts: rows naming the org in metadata (read backward through the new index, stopping after a page) and organization-resource rows that don't (read through
audit_log_resource_idx, a handful per org). The index alone isn't enough: under the singleORthe planner bitmap-ORs both indexes and sorts every org-level row of the organization buildOrgScopeCondition(single-record read, data drain) is unchanged and shares the same two definitions of an org-level row
Type of Change
- Bug fix
- Other: performance
Testing
- New
list-plans.integration.ts: many workspace-less rows from other organizations, then EXPLAINs the SQLqueryAuditLogssends (current members and departed, with and without a cursor). It asserts the metadata part reads the new index and nothing seeksworkspace_id IS NULL, and that the index serves it as a backward scan with the cursor in the index condition. Fails on the previous query list-scope.integration.tsadds metadata-only, resource-only and both-matching rows (appear once) and a resource row naming another org, and pages across all parts at several page sizes against the single-predicate reference- Autopsy: #9419's tests compared results only, on a fixture of a few dozen rows where walking every workspace-less row costs nothing; nothing asserted the org-level branch's plan
- Migration replayed with the index missing, valid and invalid; integration suites pass in migrate and push modes
bun run lint,type-check,check:audits,check-test-types,check:migrations, drizzle-kit generate (no changes)
Checklist
- Code follows project style guidelines
- Self-reviewed my changes
- Tests added/updated and passing
- No new warnings introduced
- I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)