Skip to content

fix(storage): index session list queries - #38684

Open
literally-dan wants to merge 1 commit into
anomalyco:devfrom
literally-dan:session-list-indexes
Open

fix(storage): index session list queries#38684
literally-dan wants to merge 1 commit into
anomalyco:devfrom
literally-dan:session-list-indexes

Conversation

@literally-dan

Copy link
Copy Markdown

Issue for this PR

Closes #30609

This replaces #30636, which was closed by automated cleanup. I rebased the change on the current dev branch and updated the indexes to match the queries now used by session lists.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Session lists sort by update time, but the existing indexes cover only their filter columns. The project index is now (project_id, time_updated), the root-session index is (parent_id, time_updated, id), and the global list has (time_updated, id). Project and parent lookups can still use the leftmost columns of those indexes.

The migration replaces the old single-column indexes. It also handles databases that tested the earlier single-column session_time_updated_idx.

How did you verify your code works?

bun test test/database-migration.test.ts passes all 18 tests. bun typecheck and bun script/migration.ts --check also pass in packages/core.

Screenshots / recordings

Not applicable.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@literally-dan
literally-dan force-pushed the session-list-indexes branch 3 times, most recently from 71829c9 to 1b445a0 Compare July 28, 2026 14:39
The global session list ordered by `time_updated DESC, id DESC` had no
supporting index, so every call did a full table scan plus a temp B-tree
sort. At 20k sessions that is ~32ms per list.

Add `session_time_updated_idx (time_updated, id)` and widen two existing
indexes so the project- and root-scoped variants are served the same way:

  session_project_idx      (project_id) -> (project_id, time_updated)
  session_parent_idx       (parent_id)  -> (parent_id, time_updated, id)
  session_time_updated_idx (new)        -> (time_updated, id)

Measured at 20k rows: default list 32.3ms -> 0.33ms, `roots: true`
27.2ms -> 0.34ms, project-scoped 0.97ms -> 0.35ms, with the temp B-tree
gone in all three plans. The composite index removes the sort only
because the ORDER BY reverses both columns uniformly, and `id` is a text
PRIMARY KEY rather than the rowid, so the tiebreak has to be in the
index explicitly.

The migration SQL is hand-written because drizzle-kit does not diff index
column lists. A generated migration would leave existing databases on the
narrow indexes forever while fresh databases got the wide ones from
schema.gen.ts, and `script/migration.ts --check` cannot see that drift.
The new parity test compares both paths directly.

Cost: three indexes now carry `time_updated`, where previously none did,
so a session row update goes from ~5.7us to ~19us. That is negligible
against the IO it accompanies and the session table is small.
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.

Session list and history queries do full table scans

1 participant