mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
perf(database): partial covering index for visible categories
Three queries filter on categories.hidden = false: - getGlobalRecentlyAdded — every dashboard load (now sorts by added DESC on the indexed content side after the prior CAST removal) - searchContent — Xtream search with excludeHidden - globalSearch — global Xtream search with excludeHidden All three start from content and join into categories on the category_id PK. The hidden filter is then applied per-row, requiring a row lookup for every result candidate — even before LIMIT. Add a partial covering index on categories: idx_categories_visible(id, playlist_id, type) WHERE hidden = 0. Two wins: - Covering: SQLite serves the join (id) plus filters (playlist_id, type) and the hidden = 0 predicate directly from the index without ever touching the categories row. - Partial: hidden categories are absent from the index, so they're pruned before any work happens — no row lookup, no comparison. Schema mirrored in Drizzle so the ORM stays the single source of truth. CREATE INDEX IF NOT EXISTS so existing DBs pick it up on next startup with no migration needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: f957cd9849e0
This commit is contained in:
1 parent
13acbe7e3d
commit
29fe8b905c
2 files changed
+13
No files matched your search
@@ -147,6 +147,13 @@ const CREATE_TABLE_STATEMENTS = [
|
||||
`CREATE INDEX IF NOT EXISTS idx_content_xtream ON content(xtream_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_content_type_added ON content(type, added)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_categories_type ON categories(type)`,
|
||||
// Partial covering index for visible categories — supports the dashboard's
|
||||
// getGlobalRecentlyAdded plus searchContent/globalSearch when excludeHidden
|
||||
// is set. SQLite can satisfy the join (category_id PK lookup) plus the
|
||||
// hidden = 0 filter directly from this index without touching the
|
||||
// categories row, and hidden categories are absent so they're skipped
|
||||
// before any row lookup.
|
||||
`CREATE INDEX IF NOT EXISTS idx_categories_visible ON categories(id, playlist_id, type) WHERE hidden = 0`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS favorites_content_playlist_unique ON favorites(content_id, playlist_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS favorites_playlist_idx ON favorites(playlist_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS favorites_content_idx ON favorites(content_id)`,
|
||||
|
||||
@@ -72,6 +72,12 @@ export const categories = sqliteTable(
|
||||
playlistTypeXtreamUnique: uniqueIndex(
|
||||
'categories_playlist_type_xtream_unique'
|
||||
).on(table.playlistId, table.type, table.xtreamId),
|
||||
// Partial covering index for visible categories — see connection.ts
|
||||
// for the full rationale. SQLite can satisfy joins + hidden filter
|
||||
// directly from this index for the dashboard / search queries.
|
||||
visibleIdx: index('idx_categories_visible')
|
||||
.on(table.id, table.playlistId, table.type)
|
||||
.where(sql`hidden = 0`),
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user