У меня есть два похожих запроса, которые генерируют один и тот же план запроса, за исключением того, что один план запроса выполняет сканирование кластерного индекса 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
Создает этот план:
sql-server
optimization
Seibar
источник
источник
FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'
критериям, и с тех пор в этом диапазоне было непропорционально большое количество вставок. По оценкам, для этого диапазона дат потребуется только 1,07 казней. Не 1316, которые следуют в действительности.Ответы:
JOIN после сканирования дает подсказку: с меньшим количеством строк на одной стороне последнего соединения (конечно, читая справа налево) оптимизатор выбирает «вложенный цикл», а не «хэш-соединение».
Однако, прежде чем смотреть на это, я хотел бы исключить поиск ключей и DISTINCT.
Поиск ключа: ваш индекс на FIR_Incident должен покрывать, возможно,
(FI_IncidentDate, incidentid)
или наоборот. Или есть оба и посмотреть, что используется чаще (они оба могут быть)Это
DISTINCT
является следствиемLEFT JOIN ... IS NOT NULL
. Оптимизатор уже удалил его (в планах есть «оставленные полусоединения» в финальном JOIN), но я бы использовал EXISTS для ясностиЧто-то вроде:
Вы также можете использовать руководства плана и подсказки JOIN, чтобы SQL Server использовал хеш-соединение, но сначала попытайтесь заставить его работать нормально: руководство или подсказка, вероятно, не выдержат проверку временем, поскольку они полезны только для данных и запросы, которые вы выполняете сейчас, а не в будущем
источник