Bagian dari permintaan awal Anda adalah sebagai berikut.
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)
Bagian rencana itu ditunjukkan di bawah ini
Permintaan Anda yang direvisi BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
memiliki ini untuk gabungan yang sama
Perbedaannya tampaknya yang ISNULL
menyederhanakan lebih lanjut dan sebagai hasilnya Anda mendapatkan statistik kardinalitas yang lebih akurat masuk ke gabung berikutnya. Ini adalah fungsi bernilai tabel inline dan Anda memanggilnya dengan nilai literal sehingga dapat melakukan sesuatu seperti.
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'
Dan karena ada equi join predikat b.[Date] = a.d
, rencana itu juga menunjukkan predikat kesetaraan b.[Date] = '2013-06-01'
. Akibatnya, perkiraan kardinalitas dari 28,393
baris cenderung cukup akurat.
Untuk versi CASE
/ COALESCE
kapan @dateStart
dan @dateEnd
memiliki nilai yang sama maka itu menyederhanakan OK untuk persamaan kesetaraan yang sama dan memberikan rencana yang sama tetapi kapan @dateStart = '2013-06-01'
dan @dateEnd IS NULL
hanya berjalan sejauh
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
yang juga berlaku sebagai predikat tersirat pada ColleagueList
. Perkiraan jumlah baris kali ini adalah 79.8
baris.
Bergabung berikutnya adalah
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
adalah 3,249,590
tabel baris yang (sekali lagi) ternyata tumpukan tanpa indeks yang berguna.
Perbedaan dalam estimasi ini memengaruhi pilihan bergabung yang digunakan. The ISNULL
rencana memilih hash join yang hanya memindai meja sekali. The COALESCE
rencana memilih sebuah loop bersarang bergabung dan perkiraan bahwa itu akan tetap hanya perlu memindai meja sekali dan dapat spool hasil dan memutar ulang 78 kali. yaitu memperkirakan bahwa parameter berkorelasi tidak akan berubah.
Dari kenyataan bahwa rencana loop bersarang masih berjalan setelah dua jam, asumsi pemindaian tunggal terhadap ini colleagueTime
tampaknya sangat tidak akurat.
Adapun mengapa perkiraan jumlah baris antara dua gabungan jauh lebih rendah, saya tidak yakin tanpa bisa melihat statistik di tabel. Satu-satunya cara saya berhasil memiringkan jumlah baris yang diperkirakan dalam pengujian saya adalah menambahkan banyak NULL
baris (ini mengurangi jumlah baris yang diperkirakan meskipun jumlah sebenarnya baris yang dikembalikan tetap sama).
Perkiraan jumlah baris dalam COALESCE
paket dengan data pengujian saya adalah dalam urutan
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
Atau dalam SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
tetapi ini tidak sesuai dengan komentar Anda bahwa kolom tidak memiliki NULL
nilai.