SQL Server 執行 SQL 語句的性能評估向來以 I/O 讀取數為核心指標。本文在遵循此原則的前提下,透過實際測試深入分析不同 SQL 語句執行時 SQL Server 記憶體的變化情況,結合執行計畫與 I/O 統計,為你揭示索引策略與聯接方式對記憶體佔用的實際影響。
除核心引擎進程外,SQL Server 主要佔用兩類記憶體:資料緩衝區和執行計畫快取。資料以 8KB 頁為單位存儲,與磁碟頁大小一致。查詢執行時,若所需資料已在記憶體中,直接從緩衝區讀取(邏輯讀);否則先從磁碟載入緩衝區(物理讀)。我們常關注的邏輯讀次數即對應從緩衝區讀取的頁數,物理讀則對應從磁碟讀取的頁數。
為精確觀察單條語句引起的記憶體變化,測試在無並發的獨立資料庫進行。每次測試前執行 CHECKPOINT; DBCC DROPCLEANBUFFERS 清空資料緩衝區(生產環境慎用)。並開啟 SET STATISTICS IO ON 及實際執行計畫顯示(Ctrl+M)。
SELECT * FROM P_User
執行計畫顯示 Table Scan。I/O 統計:邏輯讀 4、物理讀 4。查詢 sys.dm_os_buffer_descriptors 發現記憶體中除必要的 PFS、IAM 管理頁外,恰好出現 4 個 Data Page,與統計一致,驗證表佔用 4 個資料頁、共 1000 行。

SELECT TOP 1 * FROM P_User WHERE MobileNo = 28502
無索引時仍需掃描全表,所有資料頁均讀入記憶體。若僅 SELECT TOP 1 * FROM P_User,可能僅讀取部分頁,但因堆表無序,結果不穩定。
在 MobileNo 上建立叢集索引後,同樣查詢執行計畫變為 Clustered Index Scan。I/O 統計:邏輯讀 6、物理讀 1、預讀 4。邏輯讀增加 2 次,源於叢集索引根頁與中間頁的遍歷。記憶體中新增一個非葉級索引頁,葉級索引頁與資料頁共存。

透過 sys.dm_db_index_physical_stats 確認索引共 2 級。物理讀僅 1 次(根頁),其餘資料頁透過預讀載入,實際執行成本更低。
有叢集索引時,SELECT * FROM P_User WHERE MobileNo = 28702 僅將目標記錄所在頁讀入記憶體,極大減少 I/O 與記憶體佔用。
將叢集索引改為非叢集索引,全表掃描行為與無索引相似,查詢優化器無法利用非叢集索引,仍讀取所有資料頁。
執行計畫顯示 Index Seek + Key Lookup(覆蓋索引除外),僅讀取目標資料所在頁。
準備 P_Order 表(10000 行,38 頁)。強制 INNER LOOP JOIN:
高選擇性聯接(帶 WHERE)下,有索引表執行 Index Seek,無索引表全掃描;雙表有索引時邏輯讀極低(2-3 次)。
本測試結合記憶體變化、執行計畫與 I/O 統計,直觀驗證了索引與聯接策略對資源消耗的決定性影響,為 SQL 調優提供實證依據。