SQL Server 2017:交錯執行如何工作?
交錯執行是2017 年查詢處理器中一系列功能的一部分,其中包括:
那麼交錯執行是如何工作的呢?
魔鬼在表變數
交錯執行旨在糾正多語句表值函式中錯誤估計的基數。
在 SQL Server 的早期版本中,這些函式總是會產生相當低劣的估計:
- 2014 年、2016 年:100 行
- 2005 - 2012:1 行
不用說,這在加入其他表時可能會導致很多問題。
雖然從表變數中選擇數據本身不會抑制並行性,但低行估計通常會導致查詢成本低,而不會考慮並行性。
使用 Interleaved Execution,基數估計會暫停,MSTVF 的子樹會被執行,並以更準確的基數估計重新開始優化。
我如何知道我的 MSTVF 是否收到交錯執行。
與自適應聯接一樣,查詢計劃中會註明交錯執行。與 Adaptive Joins 不同,至少在撰寫本文時,估計的計劃中沒有註明。
具有交錯執行的 MSTVF 的計劃形狀與其中包含 MSTVF 的典型計劃有點不同。
您將在計劃頂部看到表值函式運算符,以及 TVF 運算符通常位於圖形計劃中的表變數的掃描。
將滑鼠懸停在 TVF 運算符上時,您會看到屬性
IsInterleavedExecuted
設置為 True,以及可能非常接近真實情況的估計行數。歡呼。當不發生交錯執行時,是否有任何擴展事件需要排除故障?
是的,一大堆:
請注意,其中一些位於調試通道中,在搜尋要擴展的事件時預設情況下未選擇該通道。
交錯執行是否需要列儲存索引?
不,他們會以任何方式工作。這是一個例子:
SELECT u.Id, mj.* FROM dbo.Users_cx AS u --ColumnStore JOIN dbo.MultiStatementTVF_Join(0) AS mj ON mj.UserId = u.Id WHERE u.LastAccessDate >= '2016-12-01'; SELECT u.Id, mj.* FROM dbo.Users AS u --RowStore JOIN dbo.MultiStatementTVF_Join(0) AS mj ON mj.UserId = u.Id WHERE u.LastAccessDate >= '2016-12-01';
這些查詢每個都連接到不同的表。一個列儲存,一個沒有。他們都獲得了交錯執行計劃。
交錯執行何時起作用?
目前,它僅適用於關聯在函式之外完成的 MSTVF 。
這裡有幾個例子:
此函式沒有內部相關性,這意味著沒有
WHERE
基於表列和傳入變數的子句。CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_Join ( @h BIGINT ) RETURNS @Out TABLE ( UserId INT, BadgeCount BIGINT ) AS BEGIN INSERT INTO @Out ( UserId, BadgeCount ) SELECT b.UserId, COUNT_BIG(*) AS BadgeCount FROM dbo.Badges AS b GROUP BY b.UserId HAVING COUNT_BIG(*) > @h; RETURN; END; GO
這個函式是相反的,在
UserId
帶有傳入變數的列上使用謂詞。CREATE OR ALTER FUNCTION dbo.MultiStatementTVF_CrossApply ( @h BIGINT, @id INT ) RETURNS @Out TABLE ( UserId INT, BadgeCount BIGINT ) AS BEGIN INSERT INTO @Out ( UserId, BadgeCount ) SELECT b.UserId, COUNT_BIG(*) AS BadgeCount FROM dbo.Badges AS b WHERE b.UserId = @id GROUP BY b.UserId HAVING COUNT_BIG(*) > @h; RETURN; END; GO
這是一個常見的誤解,
CROSS APPLY
不會奏效。真正的限制是前面提到的。內部功能相關性是交易破壞者。SELECT u.Id, mj.* FROM dbo.Users AS u --RowStore CROSS APPLY dbo.MultiStatementTVF_Join(0) AS mj WHERE mj.UserId = u.Id AND u.LastAccessDate >= '2016-12-01'; SELECT TOP 1 u.Id, mj.* FROM dbo.Users AS u --RowStore CROSS APPLY dbo.MultiStatementTVF_CrossApply(2147483647, u.Id) AS mj WHERE u.LastAccessDate >= '2016-12-01' ORDER BY u.Id;