對 SQL Server 而言,記憶體、磁碟、CPU 三大資源中,記憶體優先級最高。SQL Server 會盡可能將熱點資料頁緩存在記憶體中以降低 I/O。本文系統梳理 SQL Server 記憶體管理體系,分為作業系統層與 SQLOS 內部兩層次。
| 術語 | 定義 |
|---|---|
| Virtual Address Space (VAS) | 進程可定址空間。32 位元預設 2 GB 使用者模式(可透過 /3GB 啟動參數擴至 3 GB),啟用 AWE 可擴展至 64 GB(但有缺陷)。 |
| Physical Memory | 實體記憶體大小。 |
| Reserved Memory | 預留位址空間(如資料頁緩衝),不可被他用,否則存取違規。 |
| Committed Memory | 將預留頁面正式提交使用。 |
| Working Set | 進程位址空間中實際駐留在實體記憶體的部分。 |
| Page Fault | 虛擬位址不在 Working Set 時觸發。分 Hard Fault(需磁碟 I/O)與 Soft Fault(僅重新導向)。關注 Hard Fault。 |
| 層面 | 關鍵計數器 | 解讀 |
|---|---|---|
| 系統整體 | Memory: Available MBytes | 空閒實體記憶體,持續偏低則系統缺記憶體。 |
| Memory: Pages/sec | Hard Page 導致的每秒磁碟頁面讀寫總數(= Pages Input + Pages Output)。 | |
| 系統自身 | Memory: Cache Bytes | 系統 Working Set,即 OS 佔用實體記憶體。 |
| 進程級 | Process: Private Bytes | 進程提交的非共用位址空間。 |
| Process: Working Set | 進程駐留在實體記憶體的部分。 |
工具:效能監視器。參考《使用「效能監視器」監視系統效能/運行狀況》。
| 類別 | 包含項目 | 佔用特徵 |
|---|---|---|
| Database Cache (資料頁) | 8 KB 資料/索引頁 | Reserve 後 Commit,無壓力不釋放,有壓力淘汰 LRU 頁面。 |
| Consumer (功能組件) | Connection、General(編譯/鎖/中繼資料)、Query Plan、Optimizer、Utilities | 多為 Stolen 方式直接 Commit。 |
| Thread Memory | 每執行緒 0.5 MB | 固定大小,置於 MemToLeave。 |
| 第三方程式碼 | CLR、Extended Stored Procedure | 多為 Stolen,CLR 可能用 Reserve/Commit。 |

| 環境 | MemToLeave | Buffer Pool 上限 | 備註 |
|---|---|---|---|
| 32 位元 Win + 32 位元 SQL | 384 MB (256 MB + 256 * 0.5 MB * Max Worker Threads) | 1.664 GB (2 GB - 384 MB) | 啟用 AWE 可將資料頁擴展至 64 GB,但 MemToLeave 仍 384 MB |
| 64 位元 Win + 32 位元 SQL | 384 MB | 3.664 GB (4 GB - 384 MB) | 核心模式不再佔用使用者 VAS |
| 64 位元 Win + 64 位元 SQL | 無實際上限 | 無實際上限 | 按需分配,最佳選擇 |
| 計數器 | 含義 | 健康基準 |
|---|---|---|
| SQLServer:Memory Manager: Total Server Memory (KB) | Buffer Pool 提交記憶體 | 應接近 Target Server Memory |
| Target Server Memory (KB) | 可用記憶體上限(受 Max Server Memory 限制) | — |
| Memory Grants Pending | 等待記憶體授權的進程數 | 非 0 即嚴重瓶頸 |
| Buffer Cache Hit Ratio | 緩衝區命中率 | 穩定 > 98%,< 95% 表示記憶體不足 |
| Lazy Writes/sec | 每秒惰性寫入緩衝區數 | 頻繁非 0 表示記憶體壓力 |
| Page Life Expectancy (秒) | 頁面在緩衝池預期停留秒數 | 穩定高值佳,劇烈下降表示壓力 |
| Database Pages / Free Pages / Stolen Pages / Total Pages | Buffer Pool 內部結構 | Total Pages * 8 KB = Total Server Memory |
SQL Server 2005+ 統一由 Memory Clerk 管理所有記憶體申請/釋放。查詢腳本:
SELECT type,
SUM(virtual_memory_reserved_kb) AS vm_Reserved_kb,
SUM(virtual_memory_committed_kb) AS vm_Committed_kb,
SUM(awe_allocated_kb) AS awe_Allocated_kb,
SUM(shared_memory_reserved_kb) AS sm_Reserved_kb,
SUM(shared_memory_committed_kb) AS sm_Committed_kb,
SUM(single_pages_kb) AS SinglePage_kb, -- Buffer Pool 中 Stolen
SUM(multi_pages_kb) AS MultiPage_kb -- MemToLeave
FROM sys.dm_os_memory_clerks
GROUP BY type
ORDER BY type;
衍生指標:
vm_Reserved / vm_CommittedSinglePage + MultiPagevm_Committed + SinglePageMultiPage-- 跨資料庫掃描緩衝描述符
DECLARE @name NVARCHAR(100), @cmd NVARCHAR(1000);
DECLARE dbnames CURSOR FOR SELECT name FROM master.dbo.sysdatabases;
OPEN dbnames;
FETCH NEXT FROM dbnames INTO @name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @cmd = 'SELECT b.database_id, DB_NAME(b.database_id) AS db, p.object_id, p.index_id, COUNT(*) AS buffer_count '
+ 'FROM ' + @name + '.sys.allocation_units a, '
+ @name + '.sys.dm_os_buffer_descriptors b, '
+ @name + '.sys.partitions p '
+ 'WHERE a.allocation_unit_id = b.allocation_unit_id '
+ 'AND a.container_id = p.hobt_id '
+ 'AND b.database_id = DB_ID(''' + @name + ''') '
+ 'GROUP BY b.database_id, p.object_id, p.index_id '
+ 'ORDER BY b.database_id, buffer_count DESC';
EXEC (@cmd);
FETCH NEXT FROM dbnames INTO @name;
END
CLOSE dbnames; DEALLOCATE dbnames;
-- 依 object_id 查表名
SELECT s.name AS table_schema, o.name AS table_name
FROM sys.objects o JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE o.object_id = @object_id;
-- 依 index_id 查索引名
SELECT name AS index_name FROM sys.indexes WHERE object_id = @object_id AND index_id = @index_id;
SELECT usecounts, refcounts, size_in_bytes, cacheobjtype, objtype, text
FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
ORDER BY objtype DESC;
本文側重資料蒐集與架構認知,具體調優手法將在下篇(資料頁、Stolen、Multi-Page 三大壓力專題)詳細說明。