Оптимизация запросов SQL IN

У меня есть этот запрос в SQL Server, но он занимает много времени из-за предложения IN. Как я могу это оптимизировать?

DECLARE @PriorityIn TABLE ([PriorityId] [BIGINT] NOT NULL);
DECLARE @GatewayId BIGINT = 4;

INSERT INTO @PriorityIn
    SELECT PriorityId 
    FROM PriorityProviders 
    WHERE ProviderId = @GatewayId AND Type = 0

SELECT COUNT(*) 
FROM MessageIn 
WHERE ScheduleDate < GetDate() 
  AND CurrentStatus IN (0, 3, 6) 
  AND ((ProviderId IS NULL 
        AND PriorityId IN (SELECT PriorityId FROM @PriorityIn)) 
       OR ProviderId = @GatewayId);

Когда я смотрю на этот запрос, он выполняется очень быстро:

SELECT COUNT(*) 
FROM MessageIn 
WHERE ScheduleDate < GetDate() 
  AND CurrentStatus IN (0, 3, 6) 
  AND ((ProviderId IS NULL AND PriorityId IN (1, 2)) 
       OR ProviderId = @GatewayId);

Это план его выполнения:

Оптимизация запросов SQL IN

Как я могу решить эту проблему?

Попробуйте сделать PriorityId первичным ключом. Это заставляет индексировать табличную переменную и может изменить план выполнения.

Gordon Linoff 13.07.2018 15:55

Также попробуйте загрузить отдельные значения из PriorityProviders, возможно, вы загружаете слишком много повторяющихся значений.

Ilia Maskov 13.07.2018 16:03

Есть ли индекс в столбце PriorityId в таблице MessageIn?

Alejandro 13.07.2018 16:06

Да, индекс уже есть в столбце PriorityId в таблице MessageIn. В таблице PriorityProvider всего 2 записи. Но в таблице MessageIn 8 миллионов записей.

mayur Rathod 13.07.2018 16:13

Почему вы делаете это (используя табличную переменную для хранения PriorityID), когда единственное возможное значение для PriorityID - 4? Это может быть проблема XY.

Tab Alleman 13.07.2018 16:17

@TabAlleman 4 предназначен для провайдера, и я выбираю приоритеты на его основе.

mayur Rathod 13.07.2018 16:21

Я вижу, что "providerId" и "priorityId" выглядели одинаково, когда я быстро сканировал.

Tab Alleman 13.07.2018 16:22
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
7
105
2

Ответы 2

Табличные переменные почти всегда работают хуже, чем временные таблицы, из-за плохих оценок количества элементов (отсутствие статистики), сериализованных модификаций и т. д. Есть много блогов об этом, вот один, а здесь Брент Озар обсуждает некоторые различия.

Итак, измените это на временную таблицу и посмотрите, поможет ли это для начала. Чем больше строк в @PriorityIn, тем больше вероятность, что это поможет.

Я бы также заменил @GatewayId на INT, если только ProviderId не был также BIGINT. В противном случае нет причин для неявного преобразования. Это должно относиться и к PriorityId.

Кроме того, вот хороший пост в блоге о запросах и производительности кухонной мойки может ускорить его

когда я использую временные таблицы, он дает мне ответ через 11 секунд, но в случае табличных переменных он дает мне ответ через 4 секунды.

mayur Rathod 13.07.2018 16:27

Так что это 4 секунды, когда вы используете табличную переменную, что это такое, когда вы используете статические значения? Можете вставить план выполнения: brentozar.com/pastetheplan

scsimon 13.07.2018 16:28

Когда я использую статические значения, он возвращает результат через 0 секунд. Я добавил в свой вопрос.

mayur Rathod 13.07.2018 16:33

вы можете наклеить план выполнения всех трех?

scsimon 13.07.2018 16:34

План выполнения добавляется к самому вопросу.

mayur Rathod 13.07.2018 16:35

Изображения не очень помогают, поскольку мы не можем щелкнуть по ним и посмотреть, что такое prdicate, строки и т. д. Вы можете воспользоваться этой ссылкой? brentozar.com/pastetheplan

scsimon 13.07.2018 16:36

да, я уже сделал это, ниже URL: brentozar.com/pastetheplan/?id=Hk02K4L7m

mayur Rathod 13.07.2018 16:41

@mayurRathod, у меня нет. Большая часть ваших затрат исходит из подсчета (*), но я не понимаю, почему это будет быстрее, если вы укажете буквальные значения.

scsimon 16.07.2018 15:54

это то, что я вижу за последние 2 дня. кстати, спасибо за ответ на вопрос

mayur Rathod 16.07.2018 15:55

Извините, я не смог больше помочь @mayurRathod

scsimon 16.07.2018 15:57

Я только что изменил свой запрос на приведенный ниже, и теперь я получаю быстрый ответ, как будто раньше это занимало 4 секунды, а теперь это занимает 1 секунду, оба результата с 8 миллионами записей в таблице MessageIn. Но все же ищу лучший результат.

DECLARE @GatewayId INT = 4;
DECLARE @PriorityIn TABLE(
    [PriorityId] [INT] NOT NULL
);

INSERT INTO @PriorityIn
SELECT PriorityId FROM  PriorityProviders WHERE ProviderId = @GatewayId AND Type = 0


SELECT count(Id) From MessageIn m
LEFT JOIN @PriorityIn o on m.PriorityId = o.PriorityId
WHERE ScheduleDate < GetDate() AND CurrentStatus in (0,3,6) AND 
((ProviderId is null AND o.PriorityId is not null) 
OR ProviderId = @GatewayId)

Другие вопросы по теме