Чому кількість виконаних кластерних сканерів з індексом настільки велика?


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

Створює цей план: введіть тут опис зображення


Чи можете ви скопіювати / вставити запити в код коду замість файлів зображень?
Ерік Хамфрі - лоташельп

Звичайно - я додав запити, які генерують кожен план.
Сейбар

На якій таблиці відбувається кластерне сканування індексу?
Ерік Хамфрі - лоташельп

Індекс кластерного сканування на вкладений запит в з'єднання зліва (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

ПРИЄДНАЙТЕ після сканування дає підказку: при меншій кількості рядків на одній стороні останнього з'єднання (читання справа ліворуч, звичайно) оптимізатор вибирає "вкладений цикл", а не "хеш-з'єднання".

Однак перш ніж дивитися на це, я маю на меті усунути пошук ключів і DISTINCT.

  • Ключовий пошук: ваш індекс FIR_Incident повинен охоплювати, ймовірно, (FI_IncidentDate, incidentid)або навпаки. Або мати обидва і побачити, що використовується частіше (вони можуть бути обидва)

  • Це DISTINCTє наслідком LEFT JOIN ... IS NOT NULL. Оптимізатор вже видалив його (у планах "залишилося напівприєднання" на остаточному ПРИЄДНАННІ), але я б використовував 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 використовувати хеш-з'єднання, але спробуйте спочатку змусити його нормально працювати: посібник чи підказка, ймовірно, не витримає перевірку часом, оскільки вони корисні лише для даних та запити, які ви запускаєте зараз, а не в майбутньому

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.