緩衝區管理

SQL Server 資料庫的主要用途是為了儲存和擷取資料,因此大量磁碟 I/O 是 Database Engine 的核心特性。此外,因為磁碟 I/O 作業會秏用許多資源,而且相對上需要較長的時間才能完成,所以 SQL Server 非常著重提高 I/O 的效率。緩衝區管理是達成這種效率的重要元件。緩衝區管理元件包含兩種機制:可存取和更新資料庫頁面的緩衝區管理員,以及可減少資料庫檔案 I/O 的緩衝快取 (也稱為「緩衝集區」)。

緩衝區管理如何運作

緩衝區是 8 KB 的記憶體分頁,大小與資料或索引頁面相同。因此,緩衝快取也分成 8 KB 的頁面。緩衝區管理員管理從資料庫磁碟檔案將資料或索引頁面讀取到緩衝快取中,以及將修改後頁面重新寫入磁碟的功能。頁面會保留在緩衝快取中,直到緩衝區管理員需要緩衝區來讀取更多資料為止。只有資料修改後,才會重新寫入磁碟。在重新寫入磁碟之前,可以多次修改緩衝快取中的資料。如需詳細資訊,請參閱<讀取分頁>和<寫入分頁>。

SQL Server 啟動時,會根據一些參數 (如系統實體記憶體數量、設定的最大伺服器執行緒數目和各種啟動參數) 計算緩衝快取虛擬位址空間的大小。SQL Server 會為緩衝快取保留這個計算數量的處理序虛擬位址空間 (稱為「記憶體目標」),但是只會取得 (認可) 目前負載所需要的實體記憶體數量。您可以在 sys.dm_os_sys_info 目錄檢視中查詢 bpool_commit_targetbpool_committed 資料行,以分別傳回保留為記憶體目標的頁數和緩衝快取目前認可的頁數。

在 SQL Server 啟動時與緩衝快取取得記憶體目標時當中的間隔稱為「擴置」(Ramp-up)。在這段期間,讀取要求會依需要填滿緩衝區。例如,單頁讀取要求會填滿單一緩衝區頁面。這表示擴置是依據用戶端要求的數目和類型而定。擴置會將單頁讀取要求轉換成對齊的八頁要求來加速。這可讓擴置加快完成,特別是在具有大量記憶體的電腦上。

因為緩衝區管理員要使用 SQL Server 處理序中大部分的記憶體,所以會與記憶體管理員合作以允許其他元件使用其緩衝區。緩衝區管理員主要與下列元件進行互動:

  • 資源管理員,以控制整個記憶體的使用量,而在 32 位元平台中,還要控制位址空間使用量。

  • 資料庫管理員和 SQL Server 作業系統 (SQLOS),以進行低階檔案 I/O 作業。

  • 記錄檔管理員,以處理預寫記錄檔。

支援的功能

緩衝區管理員支援下列功能:

  • 緩衝區管理員為非統一記憶體存取 (NUMA) 感知。緩衝快取頁面會分散到硬體 NUMA 節點,這可讓執行緒存取本機 NUMA 節點上配置的緩衝區頁面,而不是從外部記憶體中存取。如需詳細資訊,請參閱<SQL Server 如何支援 NUMA>。若要了解如何在使用 NUMA 時指派緩衝快取中的記憶體頁數,請參閱<在 NUMA 之下放大和縮小緩衝集區>。

  • 緩衝區管理員支援熱新增記憶體 (Hot Add Memory),讓使用者不需要重新啟動伺服器即可增加實體記憶體。如需詳細資訊,請參閱<熱新增記憶體>。

  • 當啟用 AWE 時,緩衝區管理員可在 Microsoft Windows XP 及 Windows 2003 的 32 位元平台上支援動態記憶體配置。動態記憶體配置可讓 Database Engine 在緩衝快取中有效率地取得和釋放記憶體,以支援目前的工作負載。如需詳細資訊,請參閱<動態記憶體管理>。

  • 緩衝區管理員在 64 位元平台上支援大型分頁。Windows 的不同版本各有特定的頁面大小。如需詳細資訊,請參閱 Windows 文件集。

  • 緩衝區管理員提供可透過動態管理檢視公開的額外診斷資訊。您可以使用這些檢視來監視 SQL Server 特定的各種作業系統資源。例如,您可以使用 sys.dm_os_buffer_descriptors 檢視來監視緩衝快取中的頁面。如需詳細資訊,請參閱<SQL Server 作業系統相關的動態管理檢視與函數 (Transact-SQL)>。

磁碟 I/O

緩衝區管理員僅針對資料庫執行讀取和寫入。其他檔案及資料庫作業,如開啟、關閉、擴充和壓縮,都是由資料庫管理員和檔案管理員元件來執行。

緩衝區管理員執行的磁碟 I/O 作業具有下列特性:

  • 所有的 I/O 都是以非同步的方式進行,這可讓呼叫執行緒繼續進行處理,而 I/O 作業則同時於背景中執行。

  • 除非使用了 affinity I/O 選項,否則所有的 I/O 都是在呼叫執行緒中發出。affinity I/O mask 選項會將 SQL Server 磁碟 I/O 繫結到指定的 CPU 子集。在高階的 SQL Server 線上交易處理 (OLTP) 環境中,此延伸模組可強化 SQL Server 執行緒發行 I/O 的效能。

  • 多頁 I/O 是透過散佈 - 收集 I/O 來完成,可讓資料轉入或轉出非連續的記憶體區域。這表示 SQL Server 可以快速填滿或排清緩衝快取,同時還能避免多個實體 I/O 要求。

長 I/O 要求

緩衝區管理員會報告任何至少持續 15 秒仍未處理的 I/O 要求。這樣可以協助系統管理員區別 SQL Server 問題和 I/O 子系統問題。報告錯誤訊息 833,而且 SQL Server 錯誤記錄中出現如下內容:

SQL Server 發現 %d 次花費 %d 秒以上才完成的 I/O 要求,檔案:[%ls],資料庫 [%ls] (%d)。作業系統檔案控制代碼為 0x%p。最新的長 I/O 的位移為: %#016I64x。

長 I/O 可能是讀取或寫入動作;不會在目前的訊息中指出。長 I/O 訊息是警告,而非錯誤。這些訊息並不表示 SQL Server 有問題。報告這些訊息的目的是在協助系統管理員更快找到 SQL Server 回應時間遲緩的原因,並區別 SQL Server 控制範圍之外的問題。因此,不需要對它們採取任何動作,但是系統管理員應該調查 I/O 要求為何會用那麼久的時間,以及這段時間是否合理。

長 I/O 要求的原因

長 I/O 訊息可能指出 I/O 已遭永久封鎖而永遠無法完成 (稱為「遺失 I/O」),或者只是尚未完成。雖然遺失 I/O 經常導致閂鎖逾時,但也無法從訊息中辨別實際狀況是什麼。

長 I/O 通常表示 SQL Server 工作負載對磁碟子系統而言有些過重。出現下列情形時,可能表示磁碟子系統已經不勝負荷:

  • 在繁重的 SQL Server 工作負載期間,錯誤記錄出現多則長 I/O 訊息。

  • Perfmon 計數器顯示長時間的磁碟延遲、冗長的磁碟佇列或沒有磁碟閒置時間。

長 I/O 也可能是 I/O 路徑中的元件 (例如,驅動程式、控制器或韌體) 所造成,因為這個元件持續延後對舊有 I/O 要求的服務,而優先服務較接近磁碟讀寫頭目前位置的較新要求。一般以最接近讀寫頭目前位置的要求為優先處理的技術即稱為「電梯式尋軌」(Elevator Seeking)。這就很難用 Windows 系統監視器 (PERFMON.EXE) 工具來證實,因為多數情況下都應該立即服務 I/O 作業才對。執行大量循序 I/O 的工作負載,如備份與還原、資料表掃描、排序、建立索引、大量載入以及清空檔案等作業,會使長 I/O 要求的情況惡化。

顯然與上述任何情況無關的孤立長 I/O,可能是因硬體或驅動程式問題所引起。系統事件記錄檔可能會包含有助於診斷問題的相關事件。

錯誤偵測

資料庫頁面可以使用兩個選用機制 (損毀頁保護與總和檢查碼保護) 的其中一個,來確保頁面從寫入磁碟一直到再次被讀取的完整性。這些機制讓獨立的方法,不僅可以確認資料儲存媒體的正確性,而且也可以驗證硬體元件,如控制器、驅動程式、纜線,甚至作業系統。這個保護會在頁面寫入磁碟之前加諸頁面,並在從磁碟讀取頁面之後進行驗證。

損毀頁保護

在 SQL Server 2000 中導入的「損毀頁保護」,是偵測因電源故障所致頁面損毀的主要方法。例如,非預期的電源故障可能造成只有部分的頁面寫入磁碟。使用損毀頁保護時,(在複製了原始的兩個位元到頁面標頭中之後),會有個 2 位元簽章放在頁面中每個 512 位元組磁區的結尾。簽章會在每次寫入時交替使用二進位數 01 與 10,因此總是可以判斷何時未將磁區完整寫入磁碟:如果稍後讀取頁面時,位元出現錯誤的狀態,即代表頁面寫入不正確,因而可以偵測到損毀頁。損毀頁偵測會使用最少的資源,但是無法偵測磁碟硬體故障引起的所有錯誤。

總和檢查碼保護

SQL Server 2005 導入的「總和檢查碼保護」,提供更強的資料完整性檢查。總和檢查碼會針對每個頁面中寫入的資料來計算,並且儲存在頁面標頭中。每當從磁碟讀取具有已儲存總和檢查碼的頁面時,資料庫引擎會在頁面中重新計算資料的總和檢查碼,如果新的總和檢查碼與儲存的總和檢查碼不同,即引發錯誤 824。總和檢查碼保護可以比損毀頁保護捕捉更多的錯誤,因為頁面的每個位元組都會牽動它,不過相對上也需要大量的資源。啟用總和檢查碼時,緩衝區管理員任何時間從磁碟讀取頁面,都能偵測到因電源故障和有缺陷硬體或韌體所造成的錯誤。

頁面使用的保護類型是含有該頁面之資料庫的屬性。總和檢查碼保護是在 SQL Server 2005 和更新版本中建立之資料庫的預設保護。頁面保護機制是在資料庫建立期間指定,並且可以使用 ALTER DATABASE 來變更。您可以查詢 sys.databases 目錄檢視的 page_verify_option 資料行,或查詢 DATABASEPROPERTYEX 函數的 IsTornPageDetectionEnabled 屬性來判斷目前的頁面保護設定。如果變更頁面保護設定,新的設定並不會立即影響整個資料庫。反而每當頁面有資料寫入時,這些頁面還是會採用目前的資料庫保護等級。這表示資料庫可能會由具有不同保護類型的頁面組成。