perf(db): covering index for unified-inbox summary scans (deferred / needs migration) #187

Closed
opened 2026-07-03 00:40:03 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-07-03 00:40:03 +00:00 (Migrated from github.com)

Flagged by the DB access-pattern audit (from the #148 message-open profiling) as out of scope / deferred — filing to backlog so it isn't lost.

The unified-inbox summary flows SCAN the whole messages table (verified via EXPLAIN QUERY PLAN against the exported schema, 50k rows):

  • observeUnifiedFolderSummaries — SCAN messages USING INDEX index_messages_timestampMillis
  • observeUnreadCounts — SCAN messages USING INDEX index_messages_accountId_folder_uid (COUNT; index-only)
  • observeFolderSummaries — SEARCH ... index_messages_accountId_folder_uid + USE TEMP B-TREE FOR ORDER BY
  • pagingUnifiedFolderSummaries — SCAN ... index_messages_timestampMillis (bounded by LIMIT/OFFSET)

A (folder, inInbox, timestampMillis) covering index could convert these to bounded SEARCHes and drop the temp B-tree sort.

Why deferred (do NOT do this preemptively)

  • Not on the message-open/tap critical path — these stay subscribed under the reader via the mailbox VM's WhileSubscribed(5000), but tapping a message does not re-run them, so they don't cause the "opening is slow" symptom.
  • Requires a Room migration + app/schemas export + a migration test (per CLAUDE.md) — heavier and riskier than the migration-free tap-path fixes.
  • The in-repo profiling notes (docs/perf/issue-124-…md) already judged these scans not hot enough to warrant it.
  • MessageDao.observeSummaries (the one whole-table SCAN) has no production caller — it survives only as the issue-#51 CursorWindow regression-guard test.

Revisit when

Only if profiling on a very large multi-account unified inbox shows these scans becoming hot. Then the (folder, inInbox, timestampMillis) covering index (with migration + schema export + migration test) is the lever.

Flagged by the DB access-pattern audit (from the #148 message-open profiling) as **out of scope / deferred** — filing to backlog so it isn't lost. The unified-inbox summary flows `SCAN` the whole `messages` table (verified via `EXPLAIN QUERY PLAN` against the exported schema, 50k rows): - `observeUnifiedFolderSummaries` — `SCAN messages USING INDEX index_messages_timestampMillis` - `observeUnreadCounts` — `SCAN messages USING INDEX index_messages_accountId_folder_uid` (COUNT; index-only) - `observeFolderSummaries` — `SEARCH ... index_messages_accountId_folder_uid` + `USE TEMP B-TREE FOR ORDER BY` - `pagingUnifiedFolderSummaries` — `SCAN ... index_messages_timestampMillis` (bounded by LIMIT/OFFSET) A `(folder, inInbox, timestampMillis)` **covering index** could convert these to bounded `SEARCH`es and drop the temp B-tree sort. ## Why deferred (do NOT do this preemptively) - **Not on the message-open/tap critical path** — these stay subscribed under the reader via the mailbox VM's `WhileSubscribed(5000)`, but tapping a message does not re-run them, so they don't cause the "opening is slow" symptom. - **Requires a Room migration** + `app/schemas` export + a migration test (per CLAUDE.md) — heavier and riskier than the migration-free tap-path fixes. - The in-repo profiling notes (`docs/perf/issue-124-…md`) already judged these scans not hot enough to warrant it. - `MessageDao.observeSummaries` (the one whole-table `SCAN`) has **no production caller** — it survives only as the issue-#51 CursorWindow regression-guard test. ## Revisit when Only if profiling on a very large **multi-account unified inbox** shows these scans becoming hot. Then the `(folder, inInbox, timestampMillis)` covering index (with migration + schema export + migration test) is the lever.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMail#187