#c# #linq #entity-framework-core
Вопрос:
Meetings
.Include(a => a.Document)
.Include(a => a.Plan)
.Include(a => a.User)
.Include(a => a.Topics).ThenInclude(e => e.Extra)
.Include(a => a.Components).ThenInclude(g => g.Extra)
.Include(a => a.Recipients).ThenInclude(i => i.Info)
.Single(a => a.MeetingId == 1)
Приведенный выше LINQ преобразуется в SQLs с подзапросами, не имеющими фильтров:
SELECT [blah]
FROM (
SELECT TOP(2) [blah]
FROM [Meeting] AS [m]
LEFT JOIN [Plan] AS [s] ON [m].[PlanId] = [s].[PlanId]
LEFT JOIN [User] AS [u] ON [m].[UserId] = [u].[Id]
WHERE [m].[MeetingId] = 1
) AS [t]
LEFT JOIN [Document] AS [m0] ON [t].[MeetingId] = [m0].[MeetingId]
LEFT JOIN (
SELECT [blah]
FROM [Topic] AS [m1]
LEFT JOIN [Extra] AS [a] ON [m1].[ExtraId] = [a].[ExtraId]
) AS [t0] ON [t].[MeetingId] = [t0].[MeetingId]
LEFT JOIN (
SELECT [blah]
FROM [Component] AS [m2]
LEFT JOIN [Extra] AS [a0] ON [m2].[ExtraId] = [a0].[ExtraId]
) AS [t1] ON [t].[MeetingId] = [t1].[MeetingId]
LEFT JOIN (
SELECT [blah]
FROM [Recipient] AS [m3]
INNER JOIN [Info] AS [l] ON [m3].[InfoId] = [l].[InfoId]
) AS [t2] ON [t].[MeetingId] = [t2].[MeetingId]
Если вы посмотрите на последние 3 соединения, там нет фильтров, поэтому они будут сканировать всю таблицу.
Есть ли способ это исправить?
Кстати, это EF Core 3.1.
Комментарии:
1. Какие фильтры вы ожидаете? Сам
JOIN
по себе является фильтром, и в этом случае больше никаких фильтров не требуется. Поле соединения-это FK, которое обычно индексируется, поэтому не будет выполняться полное сканирование таблицы, а будет выполняться типичное сканирование диапазона индексов.2. Хотя вы действительно смотрели план выполнения запроса? Способ написания запроса и способ его выполнения редко совпадают, если только это не какой-то очень простой запрос. Последние 3 подзапроса имеют неявные фильтры, потому что они являются частью объединения; sqlserver не будет наивно запускать объединение, генерировать несколько миллионов записей, а затем сканировать их в поисках идентификатора; он знает, что их результаты будут объединены по идентификатору, и идентификатор выбран, поэтому требование к идентификатору может быть введено во внутренний запрос в качестве фильтра. Невероятно трудно победить этот механизм, даже иногда, когда вы этого хотите..
3. Есть ли способ это исправить? — во-первых, убедитесь абсолютно, что это проблема. Ничто из опубликованного до сих пор не доказывает, что это так..
4. @CaiusJard На самом деле это проблема. У LINQ есть тайм-аут для этого SQL. Я не уверен, как SQL Server справляется с этим или планом выполнения (я не разбираюсь в БД). Все, что я знаю, это: 1. время ожидания истекло 2. он возвращает мне более 7000 строк, которые в основном являются дубликатами.
5. @IvanStoev Итак , скажем, 2-й подзапрос, который присоединяется
Topic
Extra
, я ожидаюwhere
, что он фильтруетTopic
MeetingId
значение.