Частина вашого початкового запиту полягає в наступному.
FROM [dbo].[calendar] a
LEFT JOIN [dbo].[colleagueList] b
ON b.[Date] = a.d
WHERE DAY(a.[d]) = 1
AND a.[d] BETWEEN @dateStart AND COALESCE(@dateEnd,@dateStart)
Цей розділ плану показано нижче
Ваш переглянутий запит BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
має це для того ж приєднання
Відмінність полягає в тому, що ISNULL
далі спрощується, і в результаті ви отримуєте більш точну статистику про кардинальність, переходячи до наступного з'єднання. Це функція вбудованої таблиці, яку ви оцінюєте, і ви називаєте її буквальними значеннями, щоб вона могла робити щось подібне.
a.[d] BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
a.[d] BETWEEN '2013-06-01' AND ISNULL(NULL,'2013-06-01')
a.[d] BETWEEN '2013-06-01' AND '2013-06-01'
a.[d] = '2013-06-01'
А коли є предикат приєднання еквівалента, b.[Date] = a.d
план також показує предикат рівності b.[Date] = '2013-06-01'
. В результаті оцінка кардинальності 28,393
рядків, ймовірно, буде досить точною.
Для CASE
/ COALESCE
версії, коли @dateStart
і @dateEnd
є однакове значення, тоді воно спрощує ОК до того ж виразу рівності і дає той самий план, але коли @dateStart = '2013-06-01'
і @dateEnd IS NULL
це іде лише до
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
який він також застосовується як неявний присудок на ColleagueList
. Орієнтовна кількість рядків цього разу - це 79.8
рядки.
Наступним приєднанням є
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
- це 3,249,590
таблиця рядків, яка (знов), мабуть, купа без корисних індексів.
Ця невідповідність оцінок впливає на використаний вибір приєднання. ISNULL
План вибирає хеширования , який просто переглядає таблицю один раз. COALESCE
План вибирає вкладені цикли і оцінок , що він все одно буде просто необхідний сканувати таблицю один раз і мати можливість намотати результат і повторити його 78 разів. тобто він оцінює, що корельовані параметри не зміняться.
Зважаючи на те, що план вкладених циклів все ще тривав через дві години, таке припущення про одне сканування проти, colleagueTime
здається, є дуже неточним.
Щодо того, чому орієнтовна кількість рядків між двома з’єднаннями настільки нижча, я не впевнений, не маючи змоги побачити статистику на таблицях. Єдиний спосіб, коли мені вдалося перекрутити підрахунок підрахунків рядків, що значною мірою в моєму тестуванні було додавання навантаження NULL
рядків (це зменшило приблизну кількість рядків, хоча фактична кількість повернених рядків залишилася колишньою).
Орієнтовна кількість рядків у COALESCE
плані з моїми тестовими даними була в порядку
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
Або в SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
але це не суперечить вашому коментарю, що стовпець не має NULL
значень.