perf(db): the channel manager and the feed sidebar read an index, not the video heap

GET /api/channels summed every subscribed channel's videos by reading each video's heap page
(681 MB on prod): 51-61 ms warm, but 2.25 s on a first open and 6.4 s under EXPLAIN once the
table had left memory. /feed/summary and /feed/years did the same (~140 ms warm, ~800 ms cold).
Migration 0095 replaces ix_videos_channel_pub_desc with the same key INCLUDING the columns
those queries read, so they are Index Only Scans over a 25 MB index. A test holds the queries
and the index's column list together.

The admin Configuration page did a db.get per setting (two for an unset one): it now reads
every override in one query (~40 ms of ~55 on prod).
This commit is contained in:
2026-10-02 03:16:37 +02:00
parent 20010178b0
commit e995c664c6
7 changed files with 220 additions and 26 deletions
+7 -3
View File
@@ -67,19 +67,23 @@ def test_the_env_accepts_any_letter_case_and_rejects_an_unknown_value():
class _Row:
def __init__(self, value):
self.value, self.encrypted = value, False
def __init__(self, key, value):
self.key, self.value, self.encrypted = key, value, False
class _FakeDb:
"""Just enough of a Session for sysconfig's reads: one stored override row per key."""
def __init__(self, **rows):
self.rows = {k: _Row(v) for k, v in rows.items()}
self.rows = {k: _Row(k, v) for k, v in rows.items()}
def get(self, _model, key):
return self.rows.get(key)
def scalars(self, _stmt):
# describe() reads every override at once (E31 S4d).
return list(self.rows.values())
def test_a_stored_value_reads_back_canonical_and_a_stale_one_falls_back_to_the_default():
assert sysconfig.get_str(_FakeDb(plex_transcode_hw="OFF"), "plex_transcode_hw") == "off"