yes-- Jellyfin index cleanup plan (conservative, phased) -- Generated: 2026-03-08 -- Notes: -- 1) This script does NOT run automatically; execute sections manually. -- 2) Use DROP INDEX CONCURRENTLY to avoid long blocking. -- 3) Do not run inside an explicit transaction block. -- 4) Re-check stats after each phase before continuing. /* ------------------------------------------------------------------------- Baseline: capture current index usage before any change --------------------------------------------------------------------------- */ SELECT now() AS captured_at, schemaname, relname AS table_name, indexrelname AS index_name, idx_scan, idx_tup_read, idx_tup_fetch, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes WHERE schemaname IN ('library', 'authentication', 'users', 'activitylog', 'displaypreferences') ORDER BY idx_scan ASC, pg_relation_size(indexrelid) DESC; /* ------------------------------------------------------------------------- Phase 1 (lowest risk): redundant MediaStreamInfos non-unique indexes Rationale: all 0 scans since last stats reset, strong overlap among keys. --------------------------------------------------------------------------- */ -- Run one statement at a time and observe workload/latency between statements. DROP INDEX CONCURRENTLY IF EXISTS library."IX_MediaStreamInfos_StreamIndex_StreamType_Language"; DROP INDEX CONCURRENTLY IF EXISTS library."IX_MediaStreamInfos_StreamIndex_StreamType"; DROP INDEX CONCURRENTLY IF EXISTS library."IX_MediaStreamInfos_StreamIndex"; /* ------------------------------------------------------------------------- Verification checkpoint after Phase 1 --------------------------------------------------------------------------- */ SELECT now() AS check_time, schemaname, relname AS table_name, indexrelname AS index_name, idx_scan, idx_tup_read, idx_tup_fetch, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes WHERE schemaname = 'library' AND relname = 'MediaStreamInfos' ORDER BY idx_scan ASC, pg_relation_size(indexrelid) DESC; /* ------------------------------------------------------------------------- Phase 2 (medium risk): overlapping BaseItemProviders helper indexes Rationale: all 0 scans since last stats reset; candidates may be redundant with PK and alternative access paths, but monitor query plans after each. --------------------------------------------------------------------------- */ DROP INDEX CONCURRENTLY IF EXISTS library.baseitemproviders_providerid_idx; DROP INDEX CONCURRENTLY IF EXISTS library.baseitemproviders_providervalue_idx; -- Optional in Phase 2b (only if workload remains healthy after Phase 2): -- DROP INDEX CONCURRENTLY IF EXISTS library."IX_BaseItemProviders_ProviderId_ProviderValue_ItemId"; /* ------------------------------------------------------------------------- Final review query: confirm remaining low-scan indexes --------------------------------------------------------------------------- */ SELECT schemaname, relname AS table_name, indexrelname AS index_name, idx_scan, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size, pg_get_indexdef(indexrelid) AS index_definition FROM pg_stat_user_indexes WHERE schemaname IN ('library', 'authentication', 'users', 'activitylog', 'displaypreferences') ORDER BY idx_scan ASC, pg_relation_size(indexrelid) DESC; /* ------------------------------------------------------------------------- Explicitly excluded from removal in this plan: - Unique and PK-backed indexes (constraint critical) - IX_Users_Username - IX_DeviceOptions_DeviceId --------------------------------------------------------------------------- */