Ein Teil Ihrer ersten Abfrage lautet wie folgt.
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)
Dieser Abschnitt des Plans ist unten dargestellt
Ihre überarbeitete Abfrage BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
hat dies für denselben Join
Der Unterschied scheint darin zu liegen, dass er sich ISNULL
weiter vereinfacht und als Ergebnis genauere Kardinalitätsstatistiken für den nächsten Join erhalten. Dies ist eine Inline-Tabellenwertfunktion, und Sie rufen sie mit Literalwerten auf, damit sie so etwas tun kann.
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'
Und da es ein Equi-Join-Prädikat gibt b.[Date] = a.d
, zeigt der Plan auch ein Gleichheitsprädikat b.[Date] = '2013-06-01'
. Infolgedessen ist die Kardinalitätsschätzung von 28,393
Zeilen wahrscheinlich ziemlich genau.
Für die CASE
/ COALESCE
-Version, wenn @dateStart
und @dateEnd
derselbe Wert ist, vereinfacht sich OK für denselben Gleichheitsausdruck und gibt denselben Plan an, aber wann @dateStart = '2013-06-01'
und @dateEnd IS NULL
geht nur so weit wie
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
was es auch als implizites Prädikat gilt ColleagueList
. Die geschätzte Anzahl der Zeilen beträgt diesmal 79.8
Zeilen.
Der nächste Join ist
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
ist eine 3,249,590
Zeilentabelle, die (wieder) anscheinend ein Heap ohne nützliche Indizes ist.
Diese Diskrepanz bei den Schätzungen wirkt sich auf die verwendete Verknüpfungsauswahl aus. Der ISNULL
Plan wählt einen Hash-Join, der die Tabelle nur einmal scannt. Der COALESCE
Plan wählt einen Join für verschachtelte Schleifen aus und schätzt, dass die Tabelle nur noch einmal gescannt werden muss, um das Ergebnis zu spoolen und 78 Mal wiederzugeben. dh es wird geschätzt, dass sich die korrelierten Parameter nicht ändern werden.
Aufgrund der Tatsache, dass der Plan für verschachtelte Schleifen nach zwei Stunden noch lief, colleagueTime
scheint diese Annahme eines einzelnen Scans gegen sehr ungenau zu sein.
Ich bin mir nicht sicher, warum die geschätzte Anzahl der Zeilen zwischen den beiden Verknüpfungen so viel geringer ist, ohne die Statistiken in den Tabellen sehen zu können. Die einzige Möglichkeit, die geschätzten Zeilenzahlen so stark zu verzerren, bestand darin, eine NULL
Anzahl von Zeilen hinzuzufügen (dies reduzierte die geschätzte Zeilenanzahl, obwohl die tatsächliche Anzahl der zurückgegebenen Zeilen gleich blieb).
Die geschätzte Zeilenanzahl im COALESCE
Plan mit meinen Testdaten lag in der Größenordnung von
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
Oder in SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
Dies entspricht jedoch nicht Ihrem Kommentar, dass die Spalte keine NULL
Werte enthält.