Parte della query iniziale è la seguente.
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)
Quella sezione del piano è mostrata di seguito

La tua query rivista BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)ha questo per lo stesso join

La differenza sembra essere quella che ISNULLsemplifica ulteriormente e di conseguenza si ottengono statistiche sulla cardinalità più accurate andando al join successivo. Questa è una funzione con valori di tabella incorporata e la stai chiamando con valori letterali in modo che possa fare qualcosa del genere.
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'
E poiché esiste un predicato equi join, b.[Date] = a.dil piano mostra anche un predicato di uguaglianza b.[Date] = '2013-06-01'. Di conseguenza, 28,393è probabile che la stima della cardinalità delle righe sia piuttosto accurata.
Per la versione CASE/ COALESCEquando @dateStarte @dateEndhanno lo stesso valore, allora semplifica OK con la stessa espressione di uguaglianza e fornisce lo stesso piano ma quando @dateStart = '2013-06-01'e @dateEnd IS NULLva solo fino a
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
che si applica anche come predicato implicito ColleagueList. Il numero stimato di righe questa volta è 79.8righe.
Il prossimo join è
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTimeè una 3,249,590tabella di righe che è (di nuovo) apparentemente un heap senza indici utili.
Questa discrepanza nelle stime influisce sulla scelta del join utilizzata. Il ISNULLpiano sceglie un hash join che scansiona il tavolo una sola volta. Il COALESCEpiano sceglie un'unione di cicli nidificati e stima che sarà ancora necessario scansionare la tabella una volta ed essere in grado di eseguire lo spooling del risultato e riprodurlo 78 volte. cioè stima che i parametri correlati non cambieranno.
Dal fatto che il piano di cicli annidati stava ancora andando avanti dopo due ore, questa ipotesi di una singola scansione contro colleagueTimesembra essere altamente imprecisa.
Per quanto riguarda il motivo per cui il numero stimato di righe tra i due join è molto più basso, non sono sicuro senza poter vedere le statistiche sulle tabelle. L'unico modo in cui sono riuscito a distorcere i conteggi delle righe stimati così tanto nei miei test è stato l'aggiunta di un carico di NULLrighe (questo ha ridotto il conteggio delle righe stimato anche se il numero effettivo di righe restituite è rimasto lo stesso).
Il conteggio delle righe stimato nel COALESCEpiano con i miei dati di test era nell'ordine di
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
O in SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
ma questo non quadra con il tuo commento che la colonna non ha NULLvalori.