Files
pgsql-jellyfin/apply-supplementary-indexes-migration.sql
T

122 lines
4.9 KiB
PL/PgSQL

-- ================================================
-- Jellyfin PostgreSQL Migration
-- Migration: 20260227000000_AddSupplementaryIndexes
-- Purpose: Add performance indexes for improved query performance
-- ================================================
--
-- INSTRUCTIONS:
-- 1. Connect to your Jellyfin PostgreSQL database
-- 2. Run this script using psql, pgAdmin, or any PostgreSQL client
-- 3. Verify indexes are created (see verification query at end)
--
-- ================================================
BEGIN;
-- Check if migration was already applied
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM library."__EFMigrationsHistory"
WHERE "MigrationId" = '20260227000000_AddSupplementaryIndexes'
) THEN
RAISE NOTICE 'Migration 20260227000000_AddSupplementaryIndexes already applied. Skipping...';
ELSE
RAISE NOTICE 'Applying migration 20260227000000_AddSupplementaryIndexes...';
END IF;
END $$;
COMMIT;
-- ================================================
-- Create Indexes (CONCURRENTLY - safe for production)
-- ================================================
-- 1. Composite index for filtered library browsing (type + virtual + parent)
-- Use case: Browse items by type in a specific library, excluding virtual items
-- Improves queries like: "SELECT * FROM BaseItems WHERE Type='Movie' AND IsVirtualItem=false AND TopParentId='xyz'"
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_baseitems_type_isvirtualitem_topparentid
ON library."BaseItems" ("Type", "IsVirtualItem", "TopParentId")
WHERE "IsVirtualItem" = false;
-- 2. Index for folder hierarchy queries
-- Use case: Navigate folder structures efficiently
-- Improves queries like: "SELECT * FROM BaseItems WHERE TopParentId='xyz' AND IsFolder=true"
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_baseitems_topparentid_isfolder
ON library."BaseItems" ("TopParentId", "IsFolder", "IsVirtualItem")
WHERE "TopParentId" IS NOT NULL;
-- 3. Index for recently added content with filters
-- Use case: "Recently Added" view across all libraries
-- Improves queries like: "SELECT * FROM BaseItems WHERE IsVirtualItem=false ORDER BY DateCreated DESC"
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_baseitems_datecreated_filtered
ON library."BaseItems" ("DateCreated" DESC, "Type", "IsVirtualItem")
WHERE "DateCreated" IS NOT NULL AND "IsVirtualItem" = false;
-- 4. Index for reverse lookup (find items by genre/tag)
-- Use case: "Show all items with genre 'Action'"
-- Improves queries like: "SELECT ItemId FROM ItemValuesMap WHERE ItemValueId='action-genre-id'"
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_itemvaluesmap_itemvalueid_itemid
ON library."ItemValuesMap" ("ItemValueId", "ItemId");
-- 5. Index for user-specific activity queries
-- Use case: "Show activity for user X"
-- Improves queries like: "SELECT * FROM ActivityLogs WHERE UserId='user-id' ORDER BY DateCreated DESC"
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'activitylog'
AND table_name = 'ActivityLogs'
) THEN
RAISE NOTICE 'Creating activity log index...';
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_activitylogs_userid_datecreated
ON activitylog."ActivityLogs" ("UserId", "DateCreated" DESC)
WHERE "UserId" IS NOT NULL;
ELSE
RAISE NOTICE 'ActivityLogs table does not exist. Skipping activity log index.';
END IF;
END $$;
-- 6. Index for episode deduplication by PresentationUniqueKey
-- Use case: Group and deduplicate episodes (used in GetItems queries)
-- Improves queries like: "SELECT * FROM BaseItems WHERE Type='Episode' AND PresentationUniqueKey='xyz'"
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_baseitems_presentationuniquekey_episodes
ON library."BaseItems" ("PresentationUniqueKey", "TopParentId", "IsVirtualItem")
WHERE "Type" = 'MediaBrowser.Controller.Entities.TV.Episode' AND "PresentationUniqueKey" IS NOT NULL;
-- ================================================
-- Update migration history
-- ================================================
BEGIN;
INSERT INTO library."__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20260227000000_AddSupplementaryIndexes', '11.0.0')
ON CONFLICT ("MigrationId") DO NOTHING;
COMMIT;
-- ================================================
-- Verification Query
-- ================================================
-- Run this to verify all indexes were created successfully:
SELECT
schemaname AS "Schema",
tablename AS "Table",
indexname AS "Index Name",
indexdef AS "Definition"
FROM pg_indexes
WHERE indexname IN (
'idx_baseitems_type_isvirtualitem_topparentid',
'idx_baseitems_topparentid_isfolder',
'idx_baseitems_datecreated_filtered',
'idx_itemvaluesmap_itemvalueid_itemid',
'idx_activitylogs_userid_datecreated',
'idx_baseitems_presentationuniquekey_episodes'
)
ORDER BY schemaname, tablename, indexname;
-- Expected: 6 rows (or 5 if ActivityLogs table doesn't exist)