為什麼這些類似的查詢使用不同的優化階段(事務處理與快速計劃)?
此連接項中的範常式式碼
顯示一個錯誤
SELECT COUNT(*) FROM dbo.my_splitter_1('2') L1 INNER JOIN dbo.my_splitter_1('') L2 ON L1.csv_item = L2.csv_item
返回正確的結果。但以下返回不正確的結果(在 2014 年使用新的基數估計器)
SELECT (SELECT COUNT(*) FROM dbo.my_splitter_1('2') L1 INNER JOIN dbo.my_splitter_1('') L2 ON L1.csv_item = L2.csv_item)
因為它錯誤地將 L2 的結果載入到公共子表達式假離線中,然後重放 L1 結果的結果。
我很好奇為什麼兩個查詢之間的行為差異。跟踪標誌 8675 顯示成功的進入
search(0) - transaction processing
,失敗的進入search(1) - quick plan
。所以我假設附加轉換規則的可用性是行為差異的背後(例如,禁用 BuildGbApply 或GenGbApplySimple似乎可以解決它)。
但是為什麼這些非常相似的查詢的兩個計劃會遇到不同的優化階段呢?從我讀過的內容來看
search (0)
,至少需要三個表,並且在第一個範例中肯定不滿足該條件。
每個階段都有進入條件。“至少有三個表引用”是我們在給出簡單範例時所談論的入口條件之一,但不是唯一的。
一般只有基本的join和union才允許entry來查找0;標量子查詢、半連接等阻止進入搜尋 0。這個階段確實適用於非常常見的 OLTP 類型的查詢形狀。探索不太常見的事情所需的規則沒有啟用。您的範例查詢有一個標量子查詢,因此輸入失敗。
它還取決於您如何計算表引用。我從來沒有用函式深入研究過這個問題,但邏輯可能是計算表值函式以及它們產生的表變數。它甚至可以計算函式本身內部的表引用——我不確定;雖然我知道功能只是全面的艱苦工作。
這個錯誤
GenGbApplySimple
很醜陋。這種計劃形狀始終是一種可能性,但由於成本原因被拒絕,直到更改為 100 行假設表變數基數。USE PLAN
例如,可以通過提示強制在 2014 年之前的 CE 上出現有問題的計劃形狀。關於新的 Connect 項目與先前報告的問題相同,您是正確的。
舉個例子,以下查詢符合搜尋 0 的條件:
DECLARE @T AS table (c1 integer NULL); SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY U.c1) FROM ( SELECT c1 FROM @T AS T UNION SELECT c1 FROM @T AS T UNION SELECT c1 FROM @T AS T ) AS U;
做一個小的改變來包含一個標量子查詢意味著它直接搜尋 1:
DECLARE @T AS table (c1 integer NULL); SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -- Changed! FROM ( SELECT c1 FROM @T AS T UNION SELECT c1 FROM @T AS T UNION SELECT c1 FROM @T AS T ) AS U;