1abf61a05f
- Introduced PostgresSubprocessException to handle errors during PostgreSQL subprocess execution. - Refactored PostgresDatabaseProvider to improve schema initialization script discovery. - Enhanced error handling for psql command execution, including logging of output and errors. - Implemented methods to find the schema initialization script and the psql executable path.
111 lines
4.6 KiB
PL/PgSQL
111 lines
4.6 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"
|
|
-- Note: This will fail gracefully if the activitylog.ActivityLogs table doesn't exist
|
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_activitylogs_userid_datecreated
|
|
ON activitylog."ActivityLogs" ("UserId", "DateCreated" DESC)
|
|
WHERE "UserId" IS NOT NULL;
|
|
|
|
-- 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)
|