tempdb 之所以「快」,核心在於其獨特的日誌機制:Simple 復原模式、最小化記錄、系統 Checkpoint 繞過、提交無需日誌落盤。本文透過實測對比 (用戶資料庫 vs tempdb 臨時表 vs tempdb 一般表)、fn_dblog 日誌內容分析、堆積表與叢集索引表的記錄差異,深度揭示 tempdb 高效能的底層邏輯。
-- 用戶資料庫 testpage 一般表:~60 秒
-- tempdb 臨時表 #t1:~22 秒
-- tempdb 一般表 t1:~27 秒
tempdb 內操作比用戶資料庫快 2-3 倍,臨時表又比一般表快 (日誌記錄更少)。
| 特性 | 說明 | 效能影響 |
|---|---|---|
| Simple 復原模式 | 重啟無需恢復,無重做需求 | 減少日誌量 |
| 最小化記錄 | 堆積表 INSERT/UPDATE 僅記錄頁面配置,不記錄列資料 | 大幅減少日誌 I/O |
| 系統 Checkpoint 繞過 | 自動 Checkpoint 不掃描 tempdb | 避免強制日誌落盤與資料頁刷新 |
| 提交無需日誌落盤 | 資料頁刷盤前日誌可不落盤 (延遲持久化) | 交易提交極快 |
USE tempdb;
CREATE TABLE #nclst (id INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED, str1 CHAR(8000)); -- 堆積表
CREATE TABLE #clst (id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, str1 CHAR(8000)); -- 叢集表
CHECKPOINT; DBCC SHRINKFILE (N'templog', 0, TRUNCATEONLY);
INSERT INTO #nclst(str1) SELECT 'aa';
SELECT [Current LSN], Operation, Context, [Log Record Length] FROM fn_dblog(NULL,NULL) WHERE AllocUnitId IS NOT NULL;
CHECKPOINT; DBCC SHRINKFILE (N'templog', 0, TRUNCATEONLY);
INSERT INTO #clst(str1) SELECT 'aa';
SELECT [Current LSN], Operation, Context, [Log Record Length] FROM fn_dblog(NULL,NULL) WHERE AllocUnitId IS NOT NULL;
LOP_INSERT_ROWS 記錄 str1 資料,僅有頁面配置記錄。結論:tempdb 中堆積表 (無叢集索引) 享受最小化記錄,叢集索引表則完整記錄。
| 建議 | 理由 |
|---|---|
| 生產環境禁用手動 CHECKPOINT | 消耗巨大,引發效能雪崩,僅測試環境使用 |
| 避免 tempdb 中長交易 | 阻礙日誌截斷 → 日誌暴增 → 回滾失敗風險 |
| 中間表匹配優先在 tempdb 建立 | 建立快、最小化記錄、自動清理 |
| tempdb 中優先使用堆積表 | 享受最小化記錄,速度最佳 (視查詢模式評估) |
tempdb 高效能源於「犧牲持久性換取速度」:最小化記錄 + Checkpoint 繞過 + 提交不落盤。但這也意味著 tempdb 完全依賴記憶體與日誌支援回滾,日誌空間耗盡將導致實例級災難。DBA 必須守護 tempdb 日誌空間,視其為系統穩定的生命線。