Skip to content

Fix slow store_seen_flags_on_imap#8040

Merged
link2xt merged 3 commits intomainfrom
link2xt/seen-flags-sql
Mar 26, 2026
Merged

Fix slow store_seen_flags_on_imap#8040
link2xt merged 3 commits intomainfrom
link2xt/seen-flags-sql

Conversation

@link2xt
Copy link
Copy Markdown
Collaborator

@link2xt link2xt commented Mar 26, 2026

Fixes #8022

@link2xt link2xt force-pushed the link2xt/seen-flags-sql branch from ac74f67 to 85fdc95 Compare March 26, 2026 03:16
@link2xt link2xt marked this pull request as ready for review March 26, 2026 04:21
@link2xt link2xt changed the title fix: move sorting outside of SQL query in store_seen_flags_on_imap Fix slow store_seen_flags_on_imap Mar 26, 2026
@link2xt link2xt force-pushed the link2xt/seen-flags-sql branch 5 times, most recently from 0a6aff5 to bff5133 Compare March 26, 2026 11:22
Copy link
Copy Markdown
Collaborator

@adbenitez adbenitez left a comment

Choose a reason for hiding this comment

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

this fixed the problem!

link2xt added 3 commits March 26, 2026 16:07
With `ORDER BY` statement SQLite searches
the `imap` table by `transport_id` and for each found row
scans the whole `imap_markseen` table.
Number of `imap` entries for each `transport_id`
is usually large as we need to know
which UIDs to delete on IMAP server
when deleting a message.

```
sqlite> EXPLAIN QUERY PLAN
SELECT imap.id, uid, folder FROM imap, imap_markseen
WHERE imap.id = imap_markseen.id
AND imap.transport_id=?
AND target = folder
ORDER BY folder, uid;
QUERY PLAN
|--SEARCH imap USING INDEX sqlite_autoindex_imap_1 (transport_id=?)
`--SCAN imap_markseen
```

Without `ORDER BY` statement SQLite scans `imap_markseen`
table which is expected to be small,
and then searches `imap` table by `rowid` for each found result.

```
sqlite> EXPLAIN QUERY PLAN
SELECT imap.id, uid, folder FROM imap, imap_markseen
WHERE imap.id = imap_markseen.id
AND imap.transport_id=?
AND target = folder;
QUERY PLAN
|--SCAN imap_markseen
`--SEARCH imap USING INTEGER PRIMARY KEY (rowid=?)
```

Query planning was tested with SQLite 3.52.0.
It is possible to explictly make
query planner move sorting to the last step
with `ORDER +folder, +uid`, but this is not recommended
in SQLite documentation
(see <https://www.sqlite.org/optoverview.html#uplus>).

It is also possible to add indexes,
but indexes use space,
adding them requires an SQL migration,
and each index needs to be updated so it will slow down writes.
…ekeeping

Previously transports deleted via sync messages left unused `imap` entries.
// We are sorting outside of SQL to avoid SQLite constructing a query plan
// that scans the whole `imap` table. Scanning `imap_markseen` is fine
// as it should not have many items.
// If you change the SQL query, test it with `EXPLAIN QUERY PLAN`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This should goto STYLE.md i think

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I opened #8045

@link2xt link2xt merged commit b87805a into main Mar 26, 2026
55 of 56 checks passed
@link2xt link2xt deleted the link2xt/seen-flags-sql branch March 26, 2026 16:24
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.

Slow SQL query in store_seen_flags_on_imap

3 participants