Batch alternate version detection in DtoService to remove MediaSourceCount N+1

Browsing a page of videos with the MediaSourceCount field ran one alternate
version query per item, each opening a fresh DbContext. On a large library that
turned a single page into hundreds of sequential round trips and made the Items
endpoint take tens of seconds while holding a request thread the whole time.

Detect which videos own alternate versions once per page with a single query,
mirroring the existing people batch. Videos absent from that set have a single
media source, so the per item lookups are skipped for the common case. Behavior
is unchanged: a video with no alternates already resolved to a count of one.

Adds a regression test asserting the count resolves from the batch and the per
item lookups are never called.
This commit is contained in:
brandon
2026-08-07 22:51:45 -04:00
parent 70ffd25b50
commit c091ffdc6b
6 changed files with 123 additions and 12 deletions
@@ -255,6 +255,14 @@ namespace MediaBrowser.Controller.Library
/// <returns>Enumerable of linked Video items.</returns>
IEnumerable<Video> GetLinkedAlternateVersions(Video video);
/// <summary>
/// Gets, in a single query, the subset of the supplied items that own at least one alternate
/// version (local or linked). Items absent from the result have no alternate versions.
/// </summary>
/// <param name="itemIds">The item IDs to check.</param>
/// <returns>The set of item IDs that have alternate versions.</returns>
IReadOnlySet<Guid> GetItemsWithAlternateVersions(IReadOnlyList<Guid> itemIds);
/// <summary>
/// Creates or updates a LinkedChild entry linking a parent to a child item.
/// </summary>
@@ -19,6 +19,15 @@ public interface ILinkedChildrenService
/// <returns>List of child item IDs.</returns>
IReadOnlyList<Guid> GetLinkedChildrenIds(Guid parentId, int? childType = null);
/// <summary>
/// Gets, in a single query, the subset of the supplied items that own at least one alternate
/// version (local or linked). Items absent from the result have no alternate versions, so their
/// media source count is one.
/// </summary>
/// <param name="itemIds">The item IDs to check.</param>
/// <returns>The set of item IDs that have alternate versions.</returns>
IReadOnlySet<Guid> GetItemsWithAlternateVersions(IReadOnlyList<Guid> itemIds);
/// <summary>
/// Gets all artist matches from the database.
/// </summary>