Compare commits

...

2 commits

Author SHA1 Message Date
Deluan Quintão
1a74c090cd
Merge branch 'master' into perf/title-sort-covering-index 2026-07-09 22:05:53 -04:00
Deluan
ad566d0cb6 perf(db): add covering index for title-sorted song listings
Deep pagination over songs sorted by title (WHERE missing/library_id,
ORDER BY order_title LIMIT/OFFSET - the shape Jellyfin clients use to
enumerate the library, and non-admin native/Subsonic song lists share)
walked media_file_order_title and fetched the table row for every
skipped entry just to evaluate the filter and the annotation/bookmark
join keys: offset+limit random reads, seconds per page on cold spinning
disks.

The new (missing, library_id, order_title, id) index makes the offset
skip fully index-resident: filter columns and the join key come from the
index, and only the emitted page touches table rows. Measured on a
96K-track library: offset 50000 drops from ~6.5s (poisoned stats) /
~100ms (good stats, warm) to 24ms, and cold deep pages on NAS hardware
from ~7s to ~0.5s.
2026-07-08 23:29:41 -04:00

View file

@ -0,0 +1,22 @@
-- +goose Up
-- +goose StatementBegin
-- Covering index for the title-sorted, library-scoped song listing:
-- WHERE missing = ? AND library_id = ? ORDER BY order_title LIMIT n OFFSET m
-- (Jellyfin clients page through the whole library this way; non-admin native and
-- Subsonic song lists produce the same shape.)
--
-- Without it, SQLite walks media_file_order_title and must fetch the table row for
-- every *skipped* entry just to evaluate the WHERE, so a deep page costs offset+limit
-- random row reads (seconds on cold spinning disks). With the filter columns in the
-- index the skip is index-only. `id` is included because the annotation/bookmark
-- LEFT JOINs run per candidate row and need the join key; without it each skipped
-- entry still triggers a row fetch.
create index if not exists media_file_missing_library_order_title
on media_file(missing, library_id, order_title, id);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
drop index if exists media_file_missing_library_order_title;
-- +goose StatementEnd