SQL Server 的 Tempdb 分配競爭是 DBA 圈中老生常談的議題。雖然增加資料檔案數量能分散 SGAM、PFS 等系統頁的壓力,但針對系統物件(如 sysallocunits)的元資料操作競爭,在高併發場景下依然難以根治。本文將剖析游標在 Tempdb 中的特殊儲存機制——Worktable,探討其在特定場景下替代臨時表、表變數,繞過系統表記錄、降低元資料競爭的可行性。
建立一張臨時表(#t)的過程涉及多個系統頁的鎖定與更新:
刪除臨時表時上述動作逆向執行。大量併發建立/銷毀臨時物件時,SGAM、PFS、系統表頁面成為熱點。雖然 Tempdb 快取機制能緩解 IAM/資料頁分配,但系統物件操作的序列化瓶頸依然存在,連 Paul Randal 等專家也視為棘手問題。
使用 SQLQueryStress 併發建立臨時表,配合 sys.dm_os_waiting_tasks 觀察等待類型,典型出現 PAGELATCH_UP 於 2:1:53(Tempdb 第 1 檔第 53 頁)。DBCC PAGE 分析顯示該頁屬於 sysallocunits 系統物件。其他系統物件(如 sysrowsets、syscolpars)同樣易成熱點。
SELECT * INTO #t)上述手段治標不治本,因為根源在於「使用者物件建立/銷毀必經系統目錄」這一架構特性。
游標屬於 Worktable 類別,其特徵如下:
以 DBCC CHECKDB 觸發 Worktable 為例,透過 fn_dblog 觀察記錄,再用 DBCC PAGE 分析其 IAM 與資料頁,確認頁面不屬於任何系統物件,純為使用者資料頁。游標同樣使用 Worktable 儲存結果集,因此不經由 sysallocunits 等系統物件分配頁面,天然規避了上述競爭熱點。
並非所有場景皆宜以游標替代臨時表。游標適用於:
需權衡:游標帶來逐列處理開銷、鎖持有時間較長;若結果集大、可集合化操作,臨時表/表變數配合適當索引仍是首選。It depends——視具體負載特徵與瓶頸點而定。
實戰中常見陷阱:從外部複製 SQL 字串含全形空格(U+3000),SSMS 不識別為關鍵字分隔符,報錯 '' 附近有語法錯誤。現象為 SELECT 不變色、與欄位名同色。解法:刪除該位置字元並重新輸入半形空格。建議開發規範禁止直接貼上外部 SQL,或以編輯器顯示不可見字元檢查。
系統穩定運行建立在多維度平衡之上:效能瓶頸、資源消耗、回應時間、維護成本。Tempdb 競爭的終極答案不在單一技巧,而在於依負載特徵選擇最適儲存物件——臨時表、表變數、游標、記憶體最佳化表、甚至應用層快取,各有其適用邊界。DBA 與開發需共同建立「Tempdb 使用成本」意識,而非單純限制使用量。