人人都是 DBA(IV)SQL Server 內存管理


SQL Server 的內存管理是一個龐大的主題,涉及特別多的概念和技術,例如常見的 Plan Cache、Buffer Pool、Memory Clerks 等。本文僅是管中窺豹,描述常見的內存管理相關概念。

在了解內存管理之前,通過 sys.dm_os_memory_clerks 視圖可以查詢內存的使用職責(Memory Clerks),也就是內存的消耗者。

SELECT [type], SUM(pages_kb) AS total_pages_kb
FROM sys.dm_os_memory_clerks
WHERE pages_kb != 0
GROUP BY [type]
ORDER BY total_pages_kb DESC;

SQL Server 中最主要的內存組件就是緩沖池(Buffer Pool, or Bpool)。緩沖池是一個 8KB 頁面的集合,任何大於 8KB 的內存塊都需要進行單獨分配管理,例如 COM Objects、CLR Code、Extended Stored Procedures、Large Cached Plan 等。

緩沖區管理器(Buffer Manager)負責從磁盤上的數據文件中讀取數據頁(Data Page)和索引頁(Index Page),將頁數據放入 Buffer Pool 中作為數據緩存(Data Cache)。Buffer 指的是內存中的一個 Page,該 Page 的大小與數據頁或索引頁相同。

SQL Server 采用預讀機制(Read-ahead)從磁盤中讀取數據頁和索引頁至緩沖區中,以提高性能。預讀機制完全有系統內部控制,不需要進行任何配置和調整。

數據緩存(Data Cache)

數據緩存(Data Cache)中使用哈希(Hashing)方式存儲頁數據。比如給定 DatabaseID-FileNumber-PageNumber 標識符,通過哈希函數將標識符存放到哈希表中。這樣,通過哈希表(Hash Table)提供的快速檢索功能,數據庫引擎僅需要較少的內存讀取就可以判斷目標頁是否存在於緩存中,如果不存在再從磁盤中讀入緩存。

SQL Server 會將那些一段時間未被引用的頁面緩沖位置標記為空閑頁,通過空閑頁鏈表進行管理。當需要新的緩沖頁時,將從鏈表頭獲取要使用的頁地址。

每個數據緩存的頁中都包含一塊表頭區域,包含該頁最后兩次被引用的相關信息和狀態信息,例如描述該頁是否為臟頁(Dirty Page)。臟頁(Dirty Page)指的是從磁盤讀取后的數據頁被修改過。引用信息則用於實現數據緩存頁的頁面替換策略,它使用 LRU-K 算法。LRU-K 算法將有價值的緩沖區持有頁保留在活躍緩沖池中,而如果緩沖區持有頁的引用頻率不高,則這些緩沖區頁將被逐漸地釋放回空閑緩沖區列表中。

LazyWriter 線程

SQL Server 為每個 NUMA 節點都創建了一個 LazyWriter 線程,用於掃描與該節點關聯的緩沖區。LazyWriter 線程會進行周期性的睡眠和喚醒,當喚醒時將檢查空閑緩沖區列表的長度,如果低於某個閾值,將掃描整個緩沖區。在掃描過程中,當發現頁的引用率較低時,將檢查臟頁指示符。如果該頁是臟頁,則執行磁盤寫入操作。然后該頁將被釋放回空閑緩沖區列表中。

SQL Server 動態使用內存時,必須不斷地偵聽可用內存的數量,並且追蹤和監視內存的更改,以判斷何時增加或減少自身的總內存量。每當 SQL Server 中的內存增加或減少 1MB,或達到服務器內存的 5% 時,將會產生事件通知。

檢查點(Checkpoint)

檢查點(Checkpoint)線程也定期掃描緩沖區,並將臟數據頁寫入磁盤。檢查點與 LazyWriter 的區別在於,檢查點不會向空閑緩沖區列表添加空閑緩沖區。檢查點的唯一目的就是,確保將某一時刻前的頁面都寫入磁盤中,以便始終保持內存中的臟頁數量最小。

SQL Server 將檢查點的運行過程記錄到事務日志中,當 SQL Server 出現故障時,由於已寫入了某一時刻前的數據,可以減少恢復時間。

觸發檢查點的情況有:

  • 手動觸發 CHECKPOINT 命令在指定數據庫上執行檢查點。
  • 日志正在變慢,超過容量的 70%。觸發檢查點可以截斷日志並釋放日志空間。
  • 預計需要較長的恢復時間。預計恢復時間比設置的 "Recovery Interval" 選項的值要長時。如果 "Recovery Interval" 設置為 1,意味着檢查點每分鍾一次。默認值為 0,意味着 SQL Server 將選擇合適的值,通常也是 1 分鍾。
  • 請求正常關閉 SQL Server,並且不使用 NOWAIT 選項。

檢查點線程采用非順序的方式對緩沖區進行掃描。當找到一個臟頁時,會檢查該臟頁在磁盤上相鄰的頁面是否也是臟頁,以便組合進行 gather-write 大塊數據寫入,提高性能。

計划緩存(Plan Cache)

在 Buffer Pool 的緩沖區的使用組件中,除了數據緩存(Data Cache),另一個使用量最大的就是對過程與查詢計划的緩存,也就是通常說的計划緩存(Plan Cache)

SQL Server 為處數據緩存外所有其他的緩存機制提供通用緩存框架,包括儲存方式和資源監視器。儲存方式包括三種:

  1. Cache Store:計划緩存(Plan Cache)和行集(Rowset Clerk)為常見的 Cache Store。
  2. User Store:元數據緩存(Metadata Clerk)即為一種 User Store。
  3. Object Store/Memory Pool:SNI Pooling Network Buffer 即為一種 Object Store。

Cache Store 和 User Store 采用 LRU 機制來分配和釋放空間,使用 Clock 頁面置換算法來實現。而 Object Store 則只是大塊的內存,不需要 LRU 機制。

Cache Store 使用哈希表來加快查詢速度,而 User Store 則未使用哈希表,Object Store 也未使用哈希表。

通過查看 sys.dm_os_memory_cache_clock_hands 視圖,尤其是 removed_last_round_count 列,如果該值在急劇增加,那么是出現內存壓力的顯著征兆。

SELECT cache_address
    ,[name]
    ,[type]
    ,clock_hand
    ,clock_status
    ,removed_last_round_count
FROM sys.dm_os_memory_cache_clock_hands;

Memory Broker

在 SQL Server 中有大量的組件需要使用內存,為了確保每個組件都在有效的使用內存,SQL Server 使用 Memory Broker 分析與內存消耗相關的行為,並改善動態內存分配。

Memory Broker 可以在 Buffer Pool、Query Executor、Query Optimizer 等各種使用緩存的組件間調度內存分配。通過監視內存的需求與消耗,通過帶有反饋和改進機制的動態分配算法,協調各組件間形成最佳的內存分配方式。

SELECT *
FROM sys.dm_os_ring_buffers
WHERE ring_buffer_type = 'RING_BUFFER_MEMORY_BROKER';

觀察內存

  • sys.dm_os_memory_clerks 該視圖描述 SQL Server 實例中正在使用內存的組件職責。
  • sys.dm_os_memory_objects 該視圖描述 SQL Server 當前分配的內存對象。
  • sys.dm_os_memory_nodes 該視圖描述分配的 NUMA Node 相關信息。
  • sys.dm_os_memory_pools 該視圖顯示 Object Store 相關信息。
  • sys.dm_os_memory_cache_counters 該視圖描述 Cache Store 和 User Store 的運行情況快照。
  • sys.dm_os_memory_cache_hash_tables 該視圖描述活躍的緩存信息。
  • sys.dm_os_memory_cache_clock_hands 該視圖描述 Clock 頁面置換算法的相關信息。

 

《人人都是 DBA》系列文章索引:

 序號 

 名稱 

1

 人人都是 DBA(I)SQL Server 體系結構

2

 人人都是 DBA(II)SQL Server 元數據

3

 人人都是 DBA(III)SQL Server 調度器

4

 人人都是 DBA(IV)SQL Server 內存管理

5

 人人都是 DBA(V)SQL Server 數據庫文件

6

 人人都是 DBA(VI)SQL Server 事務日志

7

 人人都是 DBA(VII)B 樹和 B+ 樹

8

 人人都是 DBA(VIII)SQL Server 頁存儲結構

9

 人人都是 DBA(IX)服務器信息收集腳本匯編

10

 人人都是 DBA(X)資源信息收集腳本匯編

11

 人人都是 DBA(XI)I/O 信息收集腳本匯編

12

 人人都是 DBA(XII)查詢信息收集腳本匯編

13

 人人都是 DBA(XIII)索引信息收集腳本匯編

14

 人人都是 DBA(XIV)存儲過程信息收集腳本匯編 

15

 人人都是 DBA(XV)鎖信息收集腳本匯編

本系列文章《人人都是 DBA》由 Dennis Gao 發表自博客園個人技術博客,未經作者本人同意禁止任何形式的轉載,任何自動或人為的爬蟲轉載或抄襲行為均為耍流氓。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM