數據庫引擎-內存管理

數據庫能夠高效的讀寫硬盤上的內容,很大程度是因爲它使用了普通應用程序所沒有的內存管理機制。爲了保證性能,數據庫引擎需要將很多信息保存在內存中,典型的例子有:數據文件的位索引表;一個大表的索引頁;一個需要經常修改的表;以及數據庫本身的一些內部對象,如鎖,連接等。本文以SQL Server爲例講述數據庫的內存管理。

數據庫的內存管理是一個自動的過程,它通常儘可能多的獲取內存,直到操作系統出現內存短缺的時候。這個過程不需要管理員的干預,但可以通過參數的設置來影響這一過程。如果數據庫在一定時間裏不能獲取到處理一個查詢需要的內存,會出現查詢超時的錯誤,這時候應該提高查詢超時的等待時間值,或減少最大併發度,以減少別的查詢佔用的資源。

那麼,每個數據庫實例究竟能管理多大的內存呢?
在普通的32位機器上,每個普通進程可以管理2G的內存,可以通過設置系統地啓動配置文件,將進程中系統佔用空間限制在1G以內,從而使應用程序的用戶空間達到3G;
如果服務器上的物理內存超過了4G,可是設置AWE選項,Address Window Extension;通過這個選項,可以擴展Window的尋址方式,使其可以訪問最多64G的空間。但是如果系統的物理內存超過16G,系統需要2G的空間來維護頁表,因此不能使用之前的3G選項;

在64位服務器上,數據庫和普通應用程序一樣可以達到虛擬地址的上限,IA64體系結構可以支持7T,X64支持8T。不過不幸的是,操作系統本身並不能支持那麼大的物理內存。AWE對64位的機器沒有影響。

通過設置選項可以講數據庫的頁面鎖定在內存中,而不會被操作系統交換出去。這個選項只有在AWE設置的時候纔有效。

數據庫是如何進行內存管理的呢?
缺省行爲是獲取儘量多的內存,直到系統的Memory Notification API告知內存短缺。數據庫獲取的內存主要有兩個目的,一個是緩衝區,用於存放數據庫高效運行所需的頁面,另一個是其他目的,用於附加在數據庫進程其他外部組件,如COM等。當數據庫啓動的時候,他根據一些參數計算緩衝區的虛擬地址空間,預定這些空間,然後只獲取少量的內存以使其能夠啓動。啓動後,數據庫根據用戶連接的數量,用戶查詢的處理,不斷的增加自己的內存。這時有兩個參數會影響它,如果超過最大內存限制,那麼它會停止申請內存;如果超過最小內存限制,而且系統所需內存增加,它會釋放一些頁面。數據庫可以以幾M每秒的速度獲取和釋放內存,從而很快進行調節。

數據庫運行環境是無法預料的,而且數據的重要性是不可估計的。如何才能保證數據頁面的內容沒有被損毀呢?

它使用兩種機制檢驗一個頁面內容的正確性,第一種方法是頁面撕裂檢查,每隔512個字節,它就在後面寫上01或10,兩者交替出現。倘若512字節後看到01,再過512字節,又看到01,那麼頁面的內容必然被破壞了。這是一種比較古老的方式,它的缺點是,別人在寫的時候,你不能讀取,因爲頁面的內容已經被修改了,只有重新從硬盤上load出來,纔是正確的。在2005引入的新方法是校驗和,在頁面的頭部有頁面內容的字節校驗和,這樣在別人寫的時候,也還是可以讀的。

 

數據庫緩衝區能夠支持數據庫高效的運轉,是因爲其在讀寫方面所做的優化,這樣的優化包括提前讀和延後寫兩個方面。

什麼是提前讀?

每次數據庫讀取數據頁面的時候,會連續讀取64個相鄰的page,這樣可以減少讀硬盤的次數,但如果某個頁面已經存在於內存中,本次讀取會被拋棄。當用戶查詢需要對一個表進行掃描,那麼它會首先找到IAM,然後找到這個表的所有塊的起始地址,排序並連接成數組,最後啓動若干線程從各個地址開始進行裝載。如果對聚集索引進行掃描,它也會先掃描中間節點,根據條件找到符合條件的數據頁面的地址,將各個塊的地址分離出來,再啓動線程分別裝載。如果對非聚集索引掃描,它會邊掃描索引節點,邊發起裝載的線程,這樣掃描還沒有結束,部分節點已經裝載進來了。

有時候,幾個查詢會用到同一個大表的內容。系統會盡量使後面的查詢使用前一個裝載的頁面。這樣可以減少io。但是第二個查詢開始的頁面可能並不是這個表存在硬盤中的第一個頁面。所以對於表的查詢,如果不用order by是不能保證行的順序的。

 

什麼是延後寫?

當數據庫對內存中一個頁面發生修改後,該頁面並不會直接寫入到硬盤中,因爲它還可能被修改多次,但是每次修改都會被記錄在日誌中。在這個修改被寫入硬盤之前,數據庫首先在頁面的首尾尋找是否有相鄰頁面被修改,如果找到了32個連續的頁面,或者相鄰頁面不能被寫入硬盤,那麼尋找過程就結束了。這時候才真正開始寫操作,它通常通過三種方式完成:

懶寫,只有當緩衝區不夠時,系統將一些不經常訪問的頁面寫入到磁盤中;

迫切寫,當進行批量插入的時候,系統不記錄相關的日誌,頁面會併發的寫入硬盤;

檢查點,這應該是最常用的寫方式,檢查點進程會定期掃描緩衝區頁面,將髒頁寫入;用戶可以申請一個Cehckpoint操作,數據庫引擎也會定期產生檢查點。

這三種寫操作都是異步的,數據庫發出請求後並不會等到IO結束再返回進行後面的操作。

 

關於數據庫的內存管理還有很多內容,希望以後有機會進一步探討。

發佈了36 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章