Почему количество выполнений сканирования кластерного индекса так велико?

15

У меня есть два похожих запроса, которые генерируют один и тот же план запроса, за исключением того, что один план запроса выполняет сканирование кластерного индекса 1316 раз, а другой - 1 раз.

Единственная разница между двумя запросами - это разные критерии даты. Долгосрочный запрос фактически сужает критерии даты и тянет меньше данных.

Я определил некоторые индексы, которые помогут с обоими запросами, но я просто хочу понять, почему оператор Clustered Index Scan выполняет 1316 раз для запроса, который практически совпадает с тем, который выполняется 1 раз.

Я проверил статистику на ПК, который сканируется, и он относительно актуален.

Исходный запрос:

select distinct FIR_Incident.IncidentID
from FIR_Incident
left join (
    select incident_id as exported_incident_id
    from postnfirssummary
) exported_incidents on exported_incidents.exported_incident_id = fir_incident.incidentid
where FI_IncidentDate between '2011-06-01 00:00:00.000' and '2011-07-01 00:00:00.000'
    and exported_incidents.exported_incident_id is not null

Создает этот план: введите описание изображения здесь

После сужения критериев диапазона дат:

select distinct FIR_Incident.IncidentID
from FIR_Incident
left join (
    select incident_id as exported_incident_id
    from postnfirssummary
) exported_incidents on exported_incidents.exported_incident_id = fir_incident.incidentid
where FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'
    and exported_incidents.exported_incident_id is not null

Создает этот план: введите описание изображения здесь

Seibar
источник
Не могли бы вы скопировать / вставить ваши запросы в блок кода вместо файлов изображений?
Эрик Хамфри - LotsAhelp
Конечно - я добавил запросы, которые генерируют каждый план.
Сейбар
В какой таблице происходит сканирование кластерного индекса?
Эрик Хамфри - LotsAhelp
Сканирование кластерного индекса находится в подзапросе в левом соединении (PostNFIRSSummary)
Seibar
1
Предположительно, в последний раз, когда статистика обновлялась, была только ноль или одна строка, соответствующая FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'критериям, и с тех пор в этом диапазоне было непропорционально большое количество вставок. По оценкам, для этого диапазона дат потребуется только 1,07 казней. Не 1316, которые следуют в действительности.
Мартин Смит

Ответы:

9

JOIN после сканирования дает подсказку: с меньшим количеством строк на одной стороне последнего соединения (конечно, читая справа налево) оптимизатор выбирает «вложенный цикл», а не «хэш-соединение».

Однако, прежде чем смотреть на это, я хотел бы исключить поиск ключей и DISTINCT.

  • Поиск ключа: ваш индекс на FIR_Incident должен покрывать, возможно, (FI_IncidentDate, incidentid)или наоборот. Или есть оба и посмотреть, что используется чаще (они оба могут быть)

  • Это DISTINCTявляется следствием LEFT JOIN ... IS NOT NULL. Оптимизатор уже удалил его (в планах есть «оставленные полусоединения» в финальном JOIN), но я бы использовал EXISTS для ясности

Что-то вроде:

select 
    F.IncidentID
from 
    FIR_Incident F
where 
    exists (SELECT * FROM postnfirssummary P
           WHERE P.incident_id = F.incidentid)
    AND
    F.FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'

Вы также можете использовать руководства плана и подсказки JOIN, чтобы SQL Server использовал хеш-соединение, но сначала попытайтесь заставить его работать нормально: руководство или подсказка, вероятно, не выдержат проверку временем, поскольку они полезны только для данных и запросы, которые вы выполняете сейчас, а не в будущем

ГБН
источник