Postgres perf, path migration, and shutdown race fixes
- Major query performance boost: replaced correlated subqueries with DistinctBy() in BaseItemRepository, added episode deduplication index, and increased default command timeout to 120s. - Fixed LibraryMonitor shutdown race: added disposal checks and exception handling in FileRefresher to prevent ObjectDisposedException. - Added PowerShell and SQL utilities for fixing Linux paths in config files and database; new scripts for WebDir and path migration. - Auto-fix for WebDir in startup.json on load; new helper scripts and docs. - Added automated weekly DB performance monitoring scripts and reporting. - Expanded documentation and README for all fixes, scripts, and migration steps. - Updated SQL scripts for index creation and diagnostics; improved output handling. - Updated db-config defaults and added new diagnostic/report files.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
-- ============================================================================
|
||||
-- Optimize Indexes for Peoples and ItemValues Tables
|
||||
-- Generated: 2026-03-05
|
||||
-- Purpose: Reduce sequential scans on high-traffic tables
|
||||
-- ============================================================================
|
||||
\pset pager off
|
||||
|
||||
\echo '========================================='
|
||||
\echo 'Optimizing Peoples and ItemValues Indexes'
|
||||
\echo '========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================================================
|
||||
-- 1. PEOPLES TABLE OPTIMIZATION
|
||||
-- ============================================================================
|
||||
-- Current Issue: 144,299 sequential scans reading 13.7 BILLION rows
|
||||
-- Current Indexes: IX_Peoples_Name, PK_Peoples
|
||||
-- Target: Reduce sequential scans by 80%+
|
||||
|
||||
\echo '1. Creating Peoples Table Indexes...'
|
||||
\echo '-----------------------------------------'
|
||||
|
||||
-- Index for queries filtering by Name (case-insensitive searches)
|
||||
-- Supports ILIKE/LIKE queries
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_peoples_name_lower
|
||||
ON library."Peoples" (LOWER("Name"))
|
||||
WHERE "Name" IS NOT NULL;
|
||||
|
||||
-- Composite index for common join patterns (People -> Items)
|
||||
-- Supports queries that need both Id and Name
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_peoples_id_name
|
||||
ON library."Peoples" ("Id", "Name")
|
||||
WHERE "Name" IS NOT NULL;
|
||||
|
||||
-- Index for external ID lookups (TMDB, IMDB, etc.)
|
||||
-- Supports metadata provider queries
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_peoples_providerid
|
||||
ON library."Peoples" ("ProviderIds")
|
||||
WHERE "ProviderIds" IS NOT NULL;
|
||||
|
||||
\echo 'Peoples indexes created successfully!'
|
||||
\echo ''
|
||||
|
||||
-- ============================================================================
|
||||
-- 2. ITEMVALUES TABLE OPTIMIZATION
|
||||
-- ============================================================================
|
||||
-- Current Issue: 506,048 sequential scans reading 3.7 BILLION rows
|
||||
-- Current Indexes: IX_ItemValues_Type_CleanValue, IX_ItemValues_Type_Value
|
||||
-- Target: Increase index usage from 82% to 95%+
|
||||
|
||||
\echo '2. Creating ItemValues Table Indexes...'
|
||||
\echo '-----------------------------------------'
|
||||
|
||||
-- Index for CleanValue lookups without Type filter
|
||||
-- Supports genre/tag searches that don't filter by type
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvalues_cleanvalue
|
||||
ON library."ItemValues" ("CleanValue")
|
||||
WHERE "CleanValue" IS NOT NULL;
|
||||
|
||||
-- Index for Value lookups (with original casing)
|
||||
-- Supports exact value matches
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvalues_value
|
||||
ON library."ItemValues" ("Value")
|
||||
WHERE "Value" IS NOT NULL;
|
||||
|
||||
-- Composite index for ItemValuesMap joins
|
||||
-- Optimizes: ItemValues JOIN ItemValuesMap ON ItemValues.Id = ItemValuesMap.ItemValueId
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvalues_id_type_cleanvalue
|
||||
ON library."ItemValues" ("Id", "Type", "CleanValue");
|
||||
|
||||
-- Index for reverse lookups (find all items with specific values)
|
||||
-- Supports queries like "find all genres" or "find all tags"
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvalues_type_id
|
||||
ON library."ItemValues" ("Type", "Id")
|
||||
WHERE "Type" IS NOT NULL;
|
||||
|
||||
-- Partial index for common value types (Genre, Tags, Studio, etc.)
|
||||
-- Reduces index size while covering most common queries
|
||||
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvalues_common_types
|
||||
ON library."ItemValues" ("Type", "CleanValue", "Id")
|
||||
WHERE "Type" IN (0, 1, 2, 3, 4, 5, 6, 7, 8); -- Common metadata types
|
||||
|
||||
\echo 'ItemValues indexes created successfully!'
|
||||
\echo ''
|
||||
|
||||
-- ============================================================================
|
||||
-- 3. UPDATE STATISTICS
|
||||
-- ============================================================================
|
||||
|
||||
\echo '3. Updating Table Statistics...'
|
||||
\echo '-----------------------------------------'
|
||||
|
||||
-- Update statistics so query planner knows about new indexes
|
||||
ANALYZE VERBOSE library."Peoples";
|
||||
ANALYZE VERBOSE library."ItemValues";
|
||||
|
||||
\echo ''
|
||||
\echo '========================================='
|
||||
\echo 'Optimization Complete!'
|
||||
\echo '========================================='
|
||||
\echo ''
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. VERIFY NEW INDEXES
|
||||
-- ============================================================================
|
||||
|
||||
\echo '4. Verifying New Indexes...'
|
||||
\echo '-----------------------------------------'
|
||||
|
||||
-- Show all indexes on Peoples table
|
||||
\echo ''
|
||||
\echo 'Peoples Table Indexes:'
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
indexname,
|
||||
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
|
||||
FROM pg_stat_user_indexes
|
||||
WHERE schemaname = 'library'
|
||||
AND tablename = 'Peoples'
|
||||
ORDER BY indexname;
|
||||
|
||||
\echo ''
|
||||
\echo 'ItemValues Table Indexes:'
|
||||
-- Show all indexes on ItemValues table
|
||||
SELECT
|
||||
schemaname,
|
||||
tablename,
|
||||
indexname,
|
||||
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
|
||||
FROM pg_stat_user_indexes
|
||||
WHERE schemaname = 'library'
|
||||
AND tablename = 'ItemValues'
|
||||
ORDER BY indexname;
|
||||
|
||||
\echo ''
|
||||
\echo '========================================='
|
||||
\echo 'Next Steps:'
|
||||
\echo '1. Use Jellyfin normally for a few hours'
|
||||
\echo '2. Run: sql\diagnostics.sql'
|
||||
\echo '3. Check if sequential scans decreased'
|
||||
\echo '4. Run: sql\query-analysis.sql for slow query details'
|
||||
\echo '========================================='
|
||||
Reference in New Issue
Block a user