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:
@@ -10,6 +10,7 @@ stored in the DB and stay env-only).
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import logs, security
|
||||
@@ -307,7 +308,11 @@ def _raw_override(db: Session, key: str) -> str | None:
|
||||
per key so the operator gets a real signal without a per-request traceback. Recovery is documented in
|
||||
docs/self-hosting.md: the key must never change once secrets are stored. (B-core-2)
|
||||
"""
|
||||
row = db.get(SystemConfig, key)
|
||||
return _raw_of(db.get(SystemConfig, key), key)
|
||||
|
||||
|
||||
def _raw_of(row: SystemConfig | None, key: str) -> str | None:
|
||||
"""`_raw_override` over a row already read (describe() reads them all in one query)."""
|
||||
if row is None or row.value is None:
|
||||
return None
|
||||
if not row.encrypted:
|
||||
@@ -327,8 +332,11 @@ def _raw_override(db: Session, key: str) -> str | None:
|
||||
|
||||
def get(db: Session, key: str):
|
||||
"""Effective value: the DB override (typed) if set, else the env/config default."""
|
||||
s = _BY_KEY[key]
|
||||
raw = _raw_override(db, key)
|
||||
return _effective(_BY_KEY[key], _raw_override(db, key))
|
||||
|
||||
|
||||
def _effective(s: ConfigSpec, raw: str | None):
|
||||
"""`get` over an override already read."""
|
||||
if raw is None:
|
||||
return _default(s)
|
||||
if raw == "" and not s.allow_empty:
|
||||
@@ -420,8 +428,12 @@ def describe(db: Session) -> dict:
|
||||
"""Admin-UI metadata + current values, grouped. Secret values are never echoed —
|
||||
only whether an override is set and whether an env default exists."""
|
||||
groups: dict[str, list[dict]] = {}
|
||||
# Every override in one query: a db.get per key was one round trip each (two for a key with no
|
||||
# row, which the session cannot cache), ~40 ms of the page's ~55 on prod (E31 S4d).
|
||||
rows = {r.key: r for r in db.scalars(select(SystemConfig))}
|
||||
for s in SPECS:
|
||||
is_set = db.get(SystemConfig, s.key) is not None
|
||||
row = rows.get(s.key)
|
||||
is_set = row is not None
|
||||
item: dict = {
|
||||
"key": s.key,
|
||||
"type": s.type,
|
||||
@@ -436,7 +448,7 @@ def describe(db: Session) -> dict:
|
||||
if s.secret:
|
||||
item["default_is_set"] = bool(_default(s))
|
||||
else:
|
||||
item["value"] = get(db, s.key)
|
||||
item["value"] = _effective(s, _raw_of(row, s.key))
|
||||
item["default"] = _default(s)
|
||||
groups.setdefault(s.group, []).append(item)
|
||||
sections = [
|
||||
|
||||
Reference in New Issue
Block a user