Два явно идентичных запроса, использующие один и тот же план запроса, возвращают разное количество строк при сканировании индекса. - PullRequest
0 голосов
/ 16 июня 2020

Я пытаюсь понять, почему два запроса, использующие один и тот же план запроса, запрашивающие одни и те же данные, ведут себя по-разному.

Я исследовал следующий запрос.

select T1.id, T2.Num 
from DB1.dbo.Table1 T1, DB1.dbo.Table2 T2 
where T1.DataDate = (select MAX(datadate) from DB1.dbo.Table1)
and T1.col2 = T2.col2 
and T1.col3  = 1 
and T2.col4 = 'A string' 
order by T1.id

Table1 - это куча с одним уникальным некластеризованным индексом, основанным на данных, col2 и col3. В таблице 150 миллионов строк. Столбец datadate представляет собой столбец char (8), допускающий значение NULL и содержащий значения даты (ггггммдд).

Table2 имеет около 300 строк.

Данные в обеих таблицах были c за последние несколько недель. Статистика не обновлялась ни в одной таблице за последние несколько дней.

Проблема связана с подзапросом

(select MAX(datadate) from DB1.dbo.Table1)

, который генерирует следующую ветвь в предполагаемом плане запроса.

План запроса для сканирования большого индекса

Сюда входит сканирование индекса по уникальному индексу Table1. Это передает все 150 миллионов строк на следующий шаг (Распространение и сбор потоков). Эта версия запроса занимала в среднем 45 секунд.

Я обнаружил, что, добавив предложение «IS NOT NULL», как показано ниже -

 (select MAX(datadate) from DB1.dbo.Table1 where datadate is null) 

, ветвь плана запроса изменилась на ту, которая показана в приведенной ниже ссылке. При поиске по индексу по уникальному индексу Table1 с передачей одной строки на шаг "Top" без промежуточных шагов потока Distribute или Gather. Эта версия запроса завершилась примерно за 1 секунду.

План запроса для поиска по индексу

Пока все хорошо. Я не могу сказать, что точно понимаю, почему добавление предложения IS NOT NULL должно иметь такой драматический c эффект, но планы запросов для двух разных запросов имели для меня смысл.

Я начал путаться, когда попытался повторно запустить исходный запрос, просто чтобы убедиться, что разница в продолжительности между двумя запросами не была случайностью. Я обнаружил, что выполнение первой версии запроса (без предложения where "IS NOT NULL") в большинстве случаев занимало более 40 секунд, но время от времени оно выполнялось менее чем за 1 секунду.

Когда я посмотрел на фактический план выполнения XML двух прогонов одного и того же запроса («1-секундная версия» и «45-секундная версия»), я обнаружил следующее.

Два запроса использовали один и тот же план запроса. Я основал это на QueryPlanHa sh

QueryHash = "0xCF7F3761DC77476E" QueryPlanHash = "0x55A6B0D6E3D73607" QueryHash = "0xCF7F3761DC77476E" QueryPlanHash6E "номер 10 * 0 * 0 * 0 *, когда он пришел * 0xPlanHash =" *, когда номер * 0x5541A6 = "* 0xPlanHash =" * 0x, когда это * 0x строк, прочитанных при сканировании индекса по уникальному индексу Table1, запрос, который занял более 40 секунд, прочитал все 150 миллионов строк.

Фактический план выполнения XML - длительный запрос

Однако запрос, который занимал 1 секунду, сканировал только часть этих строк.

Фактический план выполнения XML - краткосрочный запрос

Это также может быть видно в графическом фактическом плане выполнения, при этом длительный запрос передает 150 миллионов строк из сканирования индекса

Графический фактический план выполнения - долгосрочный запрос

И " 1-секундная версия "проходит всего 14 000 строк при сканировании индекса.

Графический план фактического выполнения - краткосрочный запрос

Это различное поведение объясняет разницу в продолжительности двух запросов.

Итак, после этого длинное объяснение, мой вопрос:

Как могут два идентичных запроса, используя один и тот же план запроса, запрашивать одни и те же данные (без обновлений таблиц, задействованных между двумя запросами, без статистики обновлений между двумя запросами) вернуть другое количество строк из одного сканирования индекса?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...