Sql-Server

當我的查詢中沒有表使用任何 LOB 數據類型欄位時,為什麼 IO 統計資訊會在工作表上顯示大量 LOB 邏輯讀取?

  • April 27, 2020

我有一個過程可以在數百個數據庫中動態執行查詢,這些數據庫都具有相同的確切架構,並將結果聚合到一個臨時表中。該查詢僅涉及 3 個表(每個表在數百萬行的 10 到 100 之間,但我總共只提取了大約 50,000 行數據)。

查看查詢的聚合 IO 統計資訊(通過 StatisticsParser.com - 喊出 Richie Rump)時,它顯示創建了一個工作表,並且工作表上大約有 550,000 個 LOB 邏輯讀取。查詢中所有表的正常邏輯讀取總數略低於大約 400,000 邏輯讀取。

查詢中的實際表都沒有使用任何 LOB 數據類型,那麼這到底是什麼意思,它是我查詢中瓶頸的潛在來源嗎?

(順便說一句,我拉回的 50,000 行數據僅相當於大約 3 MB 的數據,但我的查詢在第一次執行時需要大約 10 秒才能執行(例如,當表的數據頁仍在載入到記憶體中時) ) 然後在後續執行中不到一半的時間,因此嘗試查看我是否可以始終接近 <= 4s 基準,以及這些 LOB 邏輯讀取是否與它相關。)

更新:這是一個類似的範例查詢(再次查看它,我可能已經找到了 LOB 邏輯讀取的來源)。

過程簽名: sp_StoredProc_ToGetData(@IdsTable TVP (Id INT)、@StartDate DateTime、@EndDate DateTime)

sp_StoredProc_ToGetData 內部的查詢:

SELECT Id
INTO #IdsTableTemp
FROM @IdsTable;

-- This query is ran using dynamic SQL but for the example simplicity this is just the root query itself    
SELECT 'SomeConstant' AS Field1, T1.Field2, T1.Field3, T3.Field4, T3.Field5
FROM Table1 AS T1
INNER JOIN Table2 AS T2 -- Linking table between T1 and T3
   ON T1.PrimaryKey = T2.PrimaryKey
INNER JOIN Table3 AS T3
   ON T2.NonClusteredIndexField = T3.PrimaryKey
WHERE T1.Date &gt;= @StartDate
   AND T2.Date &lt; @EndDate

**更新 2:**動態執行的主查詢的執行計劃 執行計劃

**更新 3:**電腦標量運算符屬性 計算標量運算符屬性

它總是最終成為我查看的最後一個地方,但事實證明工作表和高 LOB 邏輯讀取是由我以遞歸方式選擇的動態 SQL 變數產生的。

由於 sp_ExecuteSQL 參數的類型必須為 NVARCHAR 並且我使用 MAX 作為大小,這導致在 TempDB 中創建工作表和高 LOB 邏輯讀取。

仍然不確定為什麼當它只迭代大約 250 次遞歸時它會是 ~550,000 LOB 邏輯讀取,例如:

SELECT @DynamicSQL = @DynsmicSQL + 'My Query' 
FROM TableWithOneRecordPerInstanceThisQueryNeedsToRunFor
WHERE TableId &lt;= 250

在任何情況下,將我的動態 SQL 變數從 NVARCHAR(MAX) 更改為 NVARCHAR(4000) 都會從統計資訊中刪除所有 LOB 邏輯讀取。

根據您的問題描述:

  • 神秘的工作台
  • 高 LOB 從工作表中讀取
  • 查詢中沒有 LOB 列
  • 冷記憶體與熱記憶體不成比例地慢

聽起來您遇到了這個問題:執行計劃分析:神秘工作表

尋找一個計算標量,它在輸出時生成 LOB 數據類型,然後通過預取流入嵌套循環連接。

解決這個問題在很大程度上取決於您的源查詢,但是需要做一些事情來將 LOB 數據移過循環連接,或者可能獲得不同的連接類型。

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