Optimize BaseItemRepository docs for grouping performance
Extensively document query grouping performance issues and optimization attempts in BaseItemRepository. Add guides on PostgreSQL UUID aggregation limitations, recommended indexes, increasing database timeouts, and monitoring query performance. Current code reverts to original (slow) implementation due to EF Core/Npgsql limitations, with detailed comments and references to new docs. Provides clear workarounds and upgrade path for future `.DistinctBy()` support.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
-- Query Performance Monitoring for Jellyfin PostgreSQL Database
|
||||
-- Use these queries to identify slow operations and monitor index usage
|
||||
|
||||
-- 1. Show slow queries currently running (taking more than 5 seconds)
|
||||
SELECT
|
||||
pid,
|
||||
now() - query_start AS duration,
|
||||
state,
|
||||
wait_event_type,
|
||||
wait_event,
|
||||
LEFT(query, 100) AS query_preview
|
||||
FROM pg_stat_activity
|
||||
WHERE state != 'idle'
|
||||
AND query NOT LIKE '%pg_stat_activity%'
|
||||
AND (now() - query_start) > interval '5 seconds'
|
||||
ORDER BY duration DESC;
|
||||
|
||||
-- 2. Show index usage statistics for BaseItems table
|
||||
SELECT
|
||||
schemaname,
|
||||
reltablename,
|
||||
indexname,
|
||||
idx_scan AS index_scans,
|
||||
idx_tup_read AS tuples_read,
|
||||
idx_tup_fetch AS tuples_fetched,
|
||||
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,
|
||||
CASE
|
||||
WHEN idx_scan = 0 THEN 'UNUSED'
|
||||
WHEN idx_scan < 10 THEN 'RARELY USED'
|
||||
WHEN idx_scan < 100 THEN 'OCCASIONALLY USED'
|
||||
ELSE 'FREQUENTLY USED'
|
||||
END AS usage_level
|
||||
FROM pg_stat_user_indexes
|
||||
WHERE tablename = 'BaseItems'
|
||||
AND schemaname = 'library'
|
||||
ORDER BY idx_scan DESC, indexname;
|
||||
|
||||
-- 3. Find missing indexes (sequential scans on BaseItems)
|
||||
SELECT
|
||||
schemaname,
|
||||
reltablename,
|
||||
seq_scan AS sequential_scans,
|
||||
seq_tup_read AS rows_read_sequentially,
|
||||
idx_scan AS index_scans,
|
||||
n_tup_ins AS rows_inserted,
|
||||
n_tup_upd AS rows_updated,
|
||||
n_tup_del AS rows_deleted,
|
||||
CASE
|
||||
WHEN seq_scan > 0 AND idx_scan = 0 THEN 'INDEX NEEDED'
|
||||
WHEN seq_scan > idx_scan THEN 'MORE INDEXES MAY HELP'
|
||||
ELSE 'INDEXES WORKING WELL'
|
||||
END AS recommendation
|
||||
FROM pg_stat_user_tables
|
||||
WHERE tablename = 'BaseItems'
|
||||
AND schemaname = 'library';
|
||||
|
||||
-- 4. Show table and index sizes
|
||||
SELECT
|
||||
schemaname,
|
||||
reltablename,
|
||||
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_size,
|
||||
pg_size_pretty(pg_relation_size(schemaname||'.'||tablename)) AS table_size,
|
||||
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename) - pg_relation_size(schemaname||'.'||tablename)) AS indexes_size
|
||||
FROM pg_stat_user_tables
|
||||
WHERE tablename = 'BaseItems'
|
||||
AND schemaname = 'library';
|
||||
|
||||
-- 5. Show query statistics from pg_stat_statements (if extension is enabled)
|
||||
-- Requires: CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
||||
SELECT
|
||||
LEFT(query, 80) AS query_preview,
|
||||
calls,
|
||||
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
|
||||
ROUND(mean_exec_time::numeric, 2) AS avg_time_ms,
|
||||
ROUND(max_exec_time::numeric, 2) AS max_time_ms,
|
||||
rows
|
||||
FROM pg_stat_statements
|
||||
WHERE query LIKE '%BaseItems%'
|
||||
AND query NOT LIKE '%pg_stat%'
|
||||
ORDER BY mean_exec_time DESC
|
||||
LIMIT 20;
|
||||
|
||||
-- 6. Check for bloat in BaseItems table
|
||||
SELECT
|
||||
schemaname,
|
||||
relname,
|
||||
pg_size_pretty(pg_total_relation_size(schemaname||'.'||relname)) AS total_size,
|
||||
n_dead_tup AS dead_tuples,
|
||||
n_live_tup AS live_tuples,
|
||||
ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_tuple_percent,
|
||||
last_vacuum,
|
||||
last_autovacuum,
|
||||
CASE
|
||||
WHEN ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) > 20 THEN 'VACUUM RECOMMENDED'
|
||||
WHEN ROUND(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) > 10 THEN 'VACUUM SOON'
|
||||
ELSE 'OK'
|
||||
END AS recommendation
|
||||
FROM pg_stat_user_tables
|
||||
WHERE relname = 'BaseItems'
|
||||
AND schemaname = 'library';
|
||||
|
||||
-- 7. Show cache hit ratio (should be > 99%)
|
||||
SELECT
|
||||
schemaname,
|
||||
relname,
|
||||
heap_blks_read AS disk_reads,
|
||||
heap_blks_hit AS cache_hits,
|
||||
ROUND(100.0 * heap_blks_hit / NULLIF(heap_blks_hit + heap_blks_read, 0), 2) AS cache_hit_ratio
|
||||
FROM pg_statio_user_tables
|
||||
WHERE relname = 'BaseItems'
|
||||
AND schemaname = 'library';
|
||||
|
||||
-- 8. Reset statistics (useful after making changes to get fresh data)
|
||||
-- UNCOMMENT TO USE:
|
||||
-- SELECT pg_stat_reset();
|
||||
-- SELECT pg_stat_statements_reset(); -- If pg_stat_statements is enabled
|
||||
Reference in New Issue
Block a user