對於數據庫引擎來講,內存是一個性能提高的重要解決手段。把數據緩存起來,能夠避免在查詢或更新數據時花費多餘的時間,而這時間一般是從磁盤獲取數據時用來等待磁盤尋址的。把執行計劃緩存起來,能夠避免重複分析執行計劃時帶來額外的CPU及各類資源的開銷。經過在內存中開闢查詢內存空間,能夠迅速地完成排序、哈希等計算,達到快速返回運算結果的目的。若沒有足夠的內存空間,數據庫引擎將沒法快速地響應用戶的請求。算法
SQL Server存儲引擎自己是一個Windows下的進程,因此SQL Server使用內存和其它Windows進程同樣,都須要向Windows申請內存(經過VirtualAlloc之類的API向Windows申請內存)。sql
內存芯片提供的物理存儲空間,能被CPU直接訪問,訪問速度快,易丟失。內存性能指標GB/s,ns(納秒),前者是吞吐量,後者是響應時間。磁盤性能指標MB/s,us(微秒),從二者對比就能看出內存訪問速度是遠優於磁盤的。數據庫
物理內存容量是有限的,若是全部進程都直接使用有限的物理內存,那新的進程將沒法爲他們找到任何物理內存,那麼物理內存將容易成爲瓶頸。因此Windows會授予每一個進程一個虛擬地址空間(Virtual Address Space,VAS),經過VAS創建應用程序與物理內存的橋樑。windows
是指一個應用程序可以申請訪問的最大地址空間。VAS做爲中間的抽象層的,不是全部的請求都直接映射到物理內存,它首先映射到VAS,而後映射到物理內存。
而兩個進程能夠共用一個VAS,而VAS的大小取決於CPU架構,具體請看下面表格:api
OS Type緩存 |
Kernel Model服務器 (內核模式)網絡 |
User Model數據結構 (用戶模式)架構 |
Total |
32位系統 |
2GB |
2GB |
4GB |
64位系統 |
8TB |
8TB |
16TB |
VAS有兩種內存模式,Kernel Model和User Model。Kernel Model下的VAS是供Windows系統進程使用,而User Model下的VAS是供用戶進程使用。
由表格可知,32位Windows系統應用程序能夠訪問最大2GB的VAS,64Windows位系統能夠訪問最大8TB的VAS。這意味着在32位Windows系統中一個word文檔進程跟一個SQL Server進程能獲得最大2GB的VAS是同樣的。所以,從理論上講,這意味着任何應用程序進程在32位Windows系統上都將共享最大限度的2 G的VAS。
VMM是負責把物理內存在系統中全部須要內存的進程之間做共享,必要時會從VAS回收物理內存,把數據存儲到頁面文件上面去,保證數據永不丟失。當進程須要內存時,VMM會從頁面文件中查找數據,並將這數據寫入一部分空閒內存當中,而後將新頁面映射到須要操做的VAS當中。
SQL Server 2012對內存管理這塊跟SQL Server 2008仍是有比較大的區別的,參考一些資料,下面咱們來看看二者具體架構。
SQL Server 2008 R2: SQL Server 2012:
爲了更加清楚瞭解Buffer Pool,咱們先來了解下 SQL Server的所須要的內存有哪些,其中包括SQL Server服務(sqlserver.exe)和其它一些組件所佔用的內存,例如SQL Server代理程序(sqlagent.exe), SQL Server複製代理程序、SQL Server報表服務(ReportingServicesService.exe)、SQL Server Analysis Services(msmdsrv.exe)、SQL Server Integration Services(MsDtsSrvr.exe),和SQL Server 全文搜索(msftesql.exe)。
在一臺運行SQL Server的服務器上,運行着sqlserver服務(sqlserver.exe)和其它一些組件。在sqlserver服務(sqlserver.exe)獲取到的內存中,又分爲2大塊:一部分爲Buffer Pool,另外一部分爲非Buffer Pool,舊稱MemToReserve(默認sqlserver.exe給它預留了256MB)。下表爲這兩部份內存各自的用途:
SQL Server 進程所佔內存 |
||
Buffer Pool EXEC sp_configure N'min server memory EXEC sp_configure N'max server memory |
非Buffer Pool(即MemToReserve) (默認爲256MB), 能夠sqlserver.exe啓動時加-g參數,預留足夠內存(預留內存大小=256MB+工做線程數*512KB) |
|
Buffer Pool中主要存放以前查詢中的數據頁,和索引頁。而後根據它自已的算法,自動清理過時過訪問或效率低下的頁。 |
SQL Server工做線程 |
佔用很少 |
分佈式查詢引用的OLE DB訪問接口 |
如操做連接服務器 |
|
備份還原 |
維護計劃或者T-SQL備份恢復 |
|
擴展過程 |
如sp_或sys開頭的系統存儲過程,sp_OACreate 存儲過程 |
|
多頁的分配器SQL Server內存管理器 |
如.net framework程序(它們鏈接sqlserver的網絡包大小爲8K, sqlserver默認網絡包大小爲4k) |
|
.DLL文件 |
|
|
SQL Server CLR的Microsoft COM對象 |
這塊內存是<=8kb的存儲,適用於sql server 2008及之前,屬於Buffer Pool緩衝池來分配。有存儲數據頁面,Consumer功能組件。
這塊內存是>8kb的存儲,適用於sql server 2008及之前,不屬於Buffer Pool緩衝池來分配, 有存儲Consumer功能組件, 第三方代碼, Threads線程。
這個適用於sql server 2012及以上,整合了single-page,multi-page統稱any size page。
它來統一響應SQL Server 內部各類組件內存申請的請求。由於這個緣由,在SQL Server 2012裏面,max server memory 再也不像之前的版本那樣,只控制buffer pool的大小,也包括那些大於8kb 的內存請求。也就是,max server memory可以更準確地控制SQL Server 的內存使用了。
從內存架構咱們能夠看到有page reservation需預先申請的內存,有momory objects從windows api申請的內存,有clr第三方申請的內存。
(1)Database Cache(數據頁面緩衝區)
存放數據頁面的緩衝區。SQL Server數據庫裏的數據都是以8KB爲一個頁面存儲。當有用戶須要使用到這個頁面上存儲的數據時,SQL Server會把整個頁面都調入內存,供用戶使用。因此8KB是數據訪問的最小單元。當用戶修改了某個頁面上的數據時,SQL Server會在內存中將這個頁面修改,可是不會馬上將這個頁面寫回磁盤,而是等到後面的Checkpoint或Lazy Write的時候集中處理。
(2)各種Consumer
SQL Server的不少功能組件,都必需要申請內存來完成它們的任務。這些統稱爲「Consumer」。常見有以下:
Connection:SQL Server爲每一個鏈接分配一個數據結構,存儲關於這個鏈接的信息。另外,還會分配一個輸入緩衝池,緩衝客戶端發來的指令;一個輸出緩衝池,存放SQL Server返回的結果,等待客戶端取走。
General:一組大雜燴。包括語句的編譯、範式化、每一個鎖數據結構、事務上下文、表格和索引的元數據等。
Query Plan:語句和存儲過程的執行計劃。和Database Cache相似,若是SQL Server沒有內存壓力,它就會保留每個生成的執行計劃,供之後的用戶重用,減小Comlile的消耗。因此Query Plan也會是一塊比較大的內存使用區域。
Optimizer:SQL Server在生成執行計劃的過程當中須要消耗的內存。
Utilities:像BCP、Log Manager、Parallel Queries、Backup等比較特殊的操做須要的內存。
(3)線程內存
SQL Server會爲每一個進程內的每一個線程分配0.5MB的內存,以存放線程的數據結構和相關信息。
(4)第三方代碼申請的內存(COM,XP...)
在SQL Server的進程裏,會運行一些非SQL Server自身的代碼。例如,用戶定義的CLR或者Extended Stored Procedure代碼,Linked Server須要加載的數據連結驅動,調用SQL Mail功能須要加載的MAPI動態庫等。這些代碼也會申請內存,會算在SQL Server本身都不知道。
有些SQL Server內存的申請方式,是預先Reserve一塊大的內存,而後在使用的時候一小塊一小塊地Commit。而另外的內存申請則直接從空間裏Commit。在SQL Server裏,把後一種方式叫Stolen。
在SQL Server裏,對Database Cache,SQL Server會先Reserve,再Commit。其餘的全部內存使用,基本都是直接Commit,都是「Stolen」。要重申的是,Stolen內存也是正常使用的內存,不是泄漏掉的內存。
之因此要把這兩種分開,是由於SQL Server不會對Stolen的內存使用AWE功能。也就是說,AWE擴展出去的內存,只能用來存放Database Cache。其餘內存還要在原來的那2GB裏想辦法。
對於SQL Server本身申請的內存,有兩種內存申請單位。
小於等於8KB一個單位內存申請,SQL Server就分配一個8KB頁面。全部這些頁面都集中管理,這塊內存被稱爲Buffer Pool。一次一個頁面的這種分配稱爲Single Page Allocation。
對於大於8KB爲單位的內存申請,SQL Server把它們集中在另一個區域,稱爲Multi-Page Allocation(舊稱MemToLeave)。而這種分配稱爲Multi-Page Allocation。
類型 |
Database Cache |
Consumer |
3rh Party Code |
Threads |
Reserved/Commit |
是 |
通常不是 |
通常不是 |
不是 |
Stolen |
不是 |
是 |
是 |
是 |
Buffer Pool (Single Page) |
全部 |
絕大部分 |
沒有 |
沒有 |
MemToLeave(Multi-Page) |
沒有 |
一小部分 |
全部 |
全部 |
這裏的一個例外是運行在SQL Server進程裏的CLR代碼所申請的內存。這部份內存像第三方代碼同樣,也是使用MemToLeave的內存。可是,CLR可能也會用Reserve-Commit的方式申請內存。因此MemToLeave的內存也並非都是Stolen的。
根據SQL Server內存架構圖,咱們能夠知道,在2012版本上,Single Page Allocation跟Multi-Page Allocation合併爲Any Size Page Allocation了。而max server memory控制的不可是 Buffer Pool內存大小,而是全部大於等於小於8KB的內存請求。
如圖:
好比我設置最小服務器內存爲8G,從新啓動下SQL Server (MSSQLSERVER)服務,再使用dmv來查看當前實例的總內存空間,以及佔用內存空間:
--Target Server Memory (KB)最多能申請的內存量
--Total Server Memory (KB)目前使用了多少內存量
SELECT counter_name, ltrim(cntr_value*1.0/1024.0/1024.0)+'G'
AS memoryGB FROM sys.dm_os_performance_counters
WHERE counter_name like '%target%server%memory%'or counter_name like '%total%memory%'
從查詢結果能夠看到當咱們在SQL Server設置最小服務器內存爲8G的時候,給SQL Server分配了多少內存,它就佔用多少多少內存,從而達到性能最佳。
這是我初次學習SQL Server性能調優方面的知識,謝謝博友花陰偷移指點。不少知識點方面可能理解有誤差,但願各個路過大神指點一二。
參考文獻:
Microsoft.SQL.Server企業級平臺管理實踐
SQL Server 2012 內存管理 (memory management) 改進