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:
2026-03-01 11:33:16 -05:00
parent 23ed81b6b1
commit 623af06e46
9 changed files with 1389 additions and 28 deletions
@@ -576,29 +576,25 @@ public sealed class BaseItemRepository
// this results in "duplicate" responses for queries that try to lookup individual series or multiple versions but
// for that case the invoker has to run a DistinctBy(e => e.PresentationUniqueKey) on their own
// NOTE: This implementation uses a pattern that may generate correlated subqueries in some cases,
// which can be slow on large datasets. Attempts to optimize this with DistinctBy, MIN aggregates,
// or other patterns have failed due to EF Core translation limitations and PostgreSQL UUID constraints.
// See docs/query-optimization-complete-story.md for full details.
var enableGroupByPresentationUniqueKey = EnableGroupByPresentationUniqueKey(filter);
if (enableGroupByPresentationUniqueKey && filter.GroupBySeriesPresentationUniqueKey)
{
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
var tempQuery = dbQuery
.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey })
.Select(e => e.Min(x => x.Id));
var tempQuery = dbQuery.GroupBy(e => new { e.PresentationUniqueKey, e.SeriesPresentationUniqueKey }).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
}
else if (enableGroupByPresentationUniqueKey)
{
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
var tempQuery = dbQuery
.GroupBy(e => e.PresentationUniqueKey)
.Select(e => e.Min(x => x.Id));
var tempQuery = dbQuery.GroupBy(e => e.PresentationUniqueKey).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
}
else if (filter.GroupBySeriesPresentationUniqueKey)
{
// Optimized: Use Min(Id) instead of FirstOrDefault to avoid correlated subquery
var tempQuery = dbQuery
.GroupBy(e => e.SeriesPresentationUniqueKey)
.Select(e => e.Min(x => x.Id));
var tempQuery = dbQuery.GroupBy(e => e.SeriesPresentationUniqueKey).Select(e => e.FirstOrDefault()).Select(e => e!.Id);
dbQuery = context.BaseItems.Where(e => tempQuery.Contains(e.Id));
}
else