как я могу ускорить запрос, который ef core генерирует для создания хранимой процедуры - PullRequest
0 голосов
/ 25 мая 2020

Я использую ef core, он генерирует такой запрос:

SELECT [x].[Id],[x].[Started] AS [StartAt],(SELECT Count(*)
FROM [Message] AS [m]
WHERE [x].[Id] = [m].[ThreadId]) AS [MessageCount]
FROM [Thread] AS [x]
WHERE ( ( [x].[Started] >= '2019-11-10 00:00:00.000'/* @__startAt_0 */ )
AND ( [x].[Ended] <= '2019-11-30 00:00:00.000'/* @__endAt_1 */ ) )
AND EXISTS (SELECT 1
FROM [ThreadGroup] AS [b]
WHERE [b].[GroupId] IN ( Cast(1 AS BIGINT), Cast(2 AS BIGINT), Cast(3 AS BIGINT), Cast(4 AS BIGINT),
Cast(5 AS BIGINT), Cast(6 AS BIGINT), Cast(7 AS BIGINT), Cast(8 AS BIGINT),
Cast(9 AS BIGINT), Cast(10 AS BIGINT), Cast(11 AS BIGINT), Cast(12 AS BIGINT),
Cast(13 AS BIGINT), Cast(14 AS BIGINT), Cast(15 AS BIGINT), Cast(16 AS BIGINT),
Cast(18 AS BIGINT), Cast(19 AS BIGINT), Cast(20 AS BIGINT), Cast(21 AS BIGINT),
Cast(22 AS BIGINT), Cast(23 AS BIGINT), Cast(24 AS BIGINT), Cast(25 AS BIGINT),
Cast(26 AS BIGINT), Cast(27 AS BIGINT), Cast(28 AS BIGINT), Cast(30 AS BIGINT),
Cast(31 AS BIGINT), Cast(32 AS BIGINT), Cast(34 AS BIGINT), Cast(49 AS BIGINT) )
AND ( [x].[Id] = [b].[ThreadId] ))
ORDER BY [StartAt]
OFFSET 0 /* @__p_3 */ ROWS FETCH NEXT 20 /* @__p_4 */ ROWS ONLY

но скорость его выполнения меня не устраивает, ищу способ ускорить подобный запрос, я решил ускорить это с помощью хранимой процедуры, но оказалось, что это не помогло, так как проблема в самом "select", я пытался его переписать:

    SELECT Thread.Id, c.MessageCount  FROM Thread
        JOIN (select ThreadId from ThreadGroup where GroupId IN ( Cast(1 AS BIGINT), Cast(2 AS BIGINT),
Cast(3 AS BIGINT), Cast(4 AS BIGINT),
          Cast(5 AS BIGINT), Cast(6 AS BIGINT), Cast(7 AS BIGINT), Cast(8 AS BIGINT),
          Cast(9 AS BIGINT), Cast(10 AS BIGINT), Cast(11 AS BIGINT), Cast(12 AS BIGINT),
          Cast(13 AS BIGINT), Cast(14 AS BIGINT), Cast(15 AS BIGINT), Cast(16 AS BIGINT),
          Cast(18 AS BIGINT), Cast(19 AS BIGINT), Cast(20 AS BIGINT), Cast(21 AS BIGINT),
          Cast(22 AS BIGINT), Cast(23 AS BIGINT), Cast(24 AS BIGINT), Cast(25 AS BIGINT),
          Cast(26 AS BIGINT), Cast(27 AS BIGINT), Cast(28 AS BIGINT), Cast(30 AS BIGINT),
          Cast(31 AS BIGINT), Cast(32 AS BIGINT), Cast(34 AS BIGINT), Cast(49 AS BIGINT) )) as ThreadGroup
        ON Thread.Id = threadGroup.ThreadId
        JOIN (Select Message.ThreadId, Count(Message.ThreadId) as MessageCount from Message GROUP BY ThreadId) Mess ON Mess.ThreadId = Thread.Id
      WHERE  Thread.[Started] >= '2019-11-10 00:00:00.000' AND  Thread.[Ended] <= '2019-11-30 00:00:00.000'
      Order By Thread.Started
      OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY

но не смог ускорить, а скорее замедлить. Может кто знает как ускорить подобный запрос? Мой основной запрос ef:

var threads = _context.Threads
                .Include(x => x.ThreadGroups)
                .Include(x => x.Messages)
                .AsNoTracking()
                .Where(x => x.Started >= startAt && x.Ended <= endAt && x.ThreadGroups.Where(b => groupIds.Contains(b.GroupId)).Any())
                .GroupBy(x => x.Started);

1 Ответ

0 голосов
/ 25 мая 2020

Вам не нужно приводить все эти константы к большим int, а константы даты не нуждаются в компонентах времени. Итак, я думаю, вам нужно:

SELECT [x].[Id], [x].[Started] AS [StartAt],
       (SELECT Count(*)
        FROM [Message] [m]
        WHERE [x].[Id] = [m].[ThreadId]
       ) AS [MessageCount]
FROM [Thread] AS [x]
WHERE [x].[Started] >= '2019-11-10'AND
      [x].[Ended] < '2019-11-30' AND
      EXISTS (SELECT 1
              FROM ThreadGroup tg
              WHERE tg.[GroupId] IN ( . . . ) AND
                    [x].[Id] = tg.[ThreadId]
             )
ORDER BY [StartAt]

Для этого запроса вам нужны индексы:

  • message(threadid)
  • ThreadGroup(threadid, groupid)
  • thread(started, ended, id, startedat)

Это может помочь. Но я думаю, что вы застряли с полным сканированием таблицы на thread() и окончательной сортировкой с этой моделью данных. Все неравенства делают это медленным.

Может помочь добавить то, что кажется лишним, к where, x.started < '2019-11-30', предполагая, что started <<code>ended. Это позволит индексу ограничивать строки на основе started.

...