Sql-Server

為什麼 SQL Server 可以準確地跟踪某些多語句表值函式查詢計劃而不是其他的時間?

  • July 18, 2022

設置

對於這個展示,我使用的是2013 版本的 Stack Overflow 數據庫和 SQL Server 2022 CTP2,但它可以追溯到 SQL Server 2017,這是我想檢查的。

功能一

對於此函式,SQL Server 跟踪函式中花費的執行時間:

CREATE OR ALTER FUNCTION
   dbo.ScoreStats
(
   @UserId int
)
RETURNS
   @out table
   (
       TotalScore bigint
   )
WITH SCHEMABINDING
AS 
BEGIN

   INSERT
       @out
   (
       TotalScore
   )
   SELECT
       TotalScore = 
           SUM(x.Score)
   FROM 
   (
       SELECT
           Score = 
               SUM(p.Score)
       FROM dbo.Posts AS p
       WHERE p.OwnerUserId = @UserId

       UNION ALL

       SELECT
           Score = 
               SUM(c.Score)
       FROM dbo.Comments AS c
       WHERE c.UserId = @UserId    
   ) AS x;

   RETURN;

END;

這是查詢和執行計劃:

SELECT
   u.DisplayName,
   TotalScore = 
       (
           SELECT
               ss.TotalScore
           FROM dbo.ScoreStats(u.Id) AS ss
       )
FROM dbo.Users AS u
WHERE u.Reputation >= 1000000;

堅果

您可以看到,在查詢計劃和 Query Time Stats 屬性中都準確地跟踪了時間。

功能二

這是第二個功能,它不會發生:

CREATE OR ALTER FUNCTION
   dbo.VoteStats()
RETURNS
   @out table
   (
       PostId int,
       UpVotes int,
       DownVotes int,
       UpMultipier AS 
            UpVotes * 2
   )
WITH SCHEMABINDING
AS 
BEGIN

   INSERT
       @out
   (
       PostId,
       UpVotes,
       DownVotes
   )
   SELECT
       v.PostId,
       UpVotes = 
           SUM
           (
               CASE v.VoteTypeId
                    WHEN 2
                    THEN 1
                    ELSE 0
               END
           ),
       DownVotes = 
           SUM
           (
               CASE v.VoteTypeId
                    WHEN 3
                    THEN 1
                    ELSE 0
               END
           )
   FROM dbo.Votes AS v
   GROUP BY 
       v.PostId;

   RETURN;

END;

這是查詢和執行計劃:

SELECT TOP (100)
    p.Id,
    vs.UpVotes,
    vs.DownVotes
FROM dbo.VoteStats() AS vs
JOIN dbo.Posts AS p
   ON vs.PostId = p.Id
WHERE vs.DownVotes > vs.UpMultipier
AND   p.CommunityOwnedDate IS NULL
AND   p.ClosedDate IS NULL
ORDER BY vs.UpVotes DESC;

堅果

在此查詢中,時間沒有在圖形執行計劃中準確跟踪,而是在 Query Time Stats 屬性中進行跟踪。

MAXDOP 1 處的功能二

即使是強制連載,也無法準確跟踪時間:

SELECT TOP (100)
    p.Id,
    vs.UpVotes,
    vs.DownVotes
FROM dbo.VoteStats() AS vs
JOIN dbo.Posts AS p
   ON vs.PostId = p.Id
WHERE vs.DownVotes > vs.UpMultipier
AND   p.CommunityOwnedDate IS NULL
AND   p.ClosedDate IS NULL
ORDER BY vs.UpVotes DESC
OPTION(MAXDOP 1);

堅果

問題

回到手頭的問題:為什麼在一個查詢計劃中可以準確地跟踪時間,而在另一個查詢計劃中卻沒有?

這是使用交錯 TVF 執行的結果。

交錯執行改變了單查詢執行的優化和執行階段之間的單向邊界,並使計劃能夠根據修改後的基數估計進行調整。在優化過程中,如果我們遇到交錯執行的候選對象,即目前的多語句表值函式 (MSTVF),我們將暫停優化,執行適用的子樹,擷取准確的基數估計,然後繼續優化下游操作。

您的第一個範例不符合交錯執行的條件,但第二個範例可以。第二個範例計劃的根節點具有以下屬性:

包含候選人

第二個範例中的 TVF 人口節點具有:

交錯執行

執行帶有禁用該功能提示的測試查詢:

SELECT TOP (1) VS.* 
FROM dbo.VoteStats() AS VS
OPTION (USE HINT ('DISABLE_INTERLEAVED_EXECUTION_TVF'));

給出一個計劃,包括填充 TVF 的時間:

有時間的計劃


此問題僅在第一次執行符合交錯 TVF 執行條件的語句時發生。SQL Server 執行計劃的 TVF 填充部分,以在查詢優化期間獲得準確的基數估計。在獲得該資訊之前,不會編譯和優化計劃的其餘部分。

編譯完成後,SQL Server 不會為第一次執行重複填充表變數的工作,因為這會重複已經完成的工作(在優化期間)。不幸的是,在執行時跳過表填充意味著表變數填充的性能資訊無法以通常的方式獲得。

在後續執行中(重用計劃),SQL Server確實將表變數填充步驟作為正常查詢執行的一部分執行,因此執行時性能數字按預期顯示在 showplan 輸出中。

如果再次執行第二個範例,重用記憶體的計劃,您將看到完整的執行時性能資訊。

**注意:**此行為與智能查詢處理的交錯 TVF 執行功能特別相關。這不是 TVF 正常記憶體行為的結果,正如我在自我回答的問答中解釋的那樣SQL Server 記憶體多語句表值函式的結果嗎?.

引用自:https://dba.stackexchange.com/questions/314518