Một phần của truy vấn ban đầu của bạn là như sau.
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)
Phần đó của kế hoạch được hiển thị dưới đây

Truy vấn sửa đổi của bạn BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
có điều này cho cùng tham gia

Sự khác biệt dường như là ISNULL
đơn giản hóa hơn nữa và kết quả là bạn có được số liệu thống kê chính xác hơn về việc tham gia tiếp theo. Đây là một hàm có giá trị bảng nội tuyến và bạn đang gọi nó với các giá trị bằng chữ để nó có thể làm một cái gì đó như thế.
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'
Và vì có một vị từ tham gia đẳng thức b.[Date] = a.d
, kế hoạch cũng cho thấy một vị từ đẳng thức b.[Date] = '2013-06-01'
. Do đó, ước tính cardinality của 28,393
các hàng có thể khá chính xác.
Đối với phiên bản CASE
/ COALESCE
khi @dateStart
và @dateEnd
có cùng giá trị thì nó đơn giản hóa OK cho cùng một biểu thức đẳng thức và đưa ra cùng một kế hoạch nhưng khi @dateStart = '2013-06-01'
và @dateEnd IS NULL
nó chỉ đi xa đến mức
a.[d]>='2013-06-01' AND a.[Date]<=CASE WHEN (1) THEN '2013-06-01' ELSE NULL END
mà nó cũng được áp dụng như là một vị ngữ ngụ ý trên ColleagueList
. Số lượng hàng ước tính lần này là 79.8
hàng.
Sự tham gia tiếp theo cùng là
LEFT JOIN colleagueTime
ON colleagueTime.TC_DATE = colleagueList.Date
AND colleagueTime.ASSOC_ID = CAST(colleagueList.ID AS VARCHAR(10))
colleagueTime
là một 3,249,590
bảng hàng (một lần nữa) rõ ràng là một đống không có chỉ mục hữu ích.
Sự khác biệt trong ước tính này ảnh hưởng đến sự lựa chọn tham gia được sử dụng. Các ISNULL
kế hoạch chọn một băm tham gia mà chỉ quét bảng một lần. Các COALESCE
kế hoạch chọn một vòng lặp lồng nhau tham gia và ước tính rằng nó sẽ vẫn chỉ cần quét các bảng một lần và có thể ống chỉ kết quả và phát lại nó 78 lần. tức là nó ước tính rằng các tham số tương quan sẽ không thay đổi.
Từ thực tế là kế hoạch các vòng lặp lồng nhau vẫn đang diễn ra sau hai giờ, giả định này về một lần quét chống lại colleagueTime
dường như rất không chính xác.
Về lý do tại sao số lượng hàng ước tính giữa hai liên kết thấp hơn rất nhiều, tôi không chắc chắn nếu không thể xem số liệu thống kê trên các bảng. Cách duy nhất tôi quản lý để làm lệch số lượng hàng ước tính mà phần lớn trong thử nghiệm của tôi là thêm một tải NULL
hàng (điều này làm giảm số lượng hàng ước tính mặc dù số lượng hàng thực tế được trả lại vẫn giữ nguyên).
Số lượng hàng ước tính trong COALESCE
kế hoạch với dữ liệu thử nghiệm của tôi là theo thứ tự
number of rows matching >= condition * 30% * (proportion of rows in the table not null)
Hoặc trong SQL
SELECT 1E0 * COUNT([Date]) / COUNT(*) * ( COUNT(CASE
WHEN [Date] >= '2013-06-01' THEN 1
END) * 0.30 )
FROM [dbo].[colleagueList]
nhưng điều này không vuông với nhận xét của bạn rằng cột không có NULL
giá trị.