SQL Server資源管理以內存管理篇(上)

對SQL Server來講,最重要的資源是內存、Disk和CPU,其中內存又是重中之重,由於SQL Server爲了性能要求,會將它所要訪問的數據所有(只要內存足夠)放到緩存中。這篇就來介紹SQL Server的內存管理體系。html

SQL Server做爲Windows上運行的應用程序,必須接受Windows的資源管理,利用Windows的API來申請和調度各種資源。可是,因爲Windows的資源管理體系,是爲了知足大多數的應用程序所設計的,這對於SQL Server這種定位於企業級、支持多用戶和高併發性的數據庫應用程序來講不是很適合,爲此SQL Server開發了本身的一套資源管理體系——SQLOS(SQL操做系統)。也就是說SQL Server的資源管理分兩層,第一層是在Windows上,經過Windows的API來申請資源。第二層是在SQL Server上,利用SQLOS來決定如何使用從Windows那裏申請來的資源。sql

1、操做系統層面的SQL Server內存管理數據庫

因爲SQL server的內存是經過Windows的API來申請的,若是Windows本身自己就缺乏內存,SQL Server因爲申請不到內存,性能天然受影響。所以作SQL Server的內存檢測,第一步就是查看系統層面的內存,以確保系統自己不缺內存,這一步簡單可是必不可少。這裏先介紹Windows的一些內存管理理念,而後介紹如何檢查系統的內存狀況。緩存

一、Windows的一些內存術語服務器

Virtual Address Space(虛擬地址空間):應用程序可以申請訪問的最大地址空間。對於32位的服務器,地址尋址空間爲2的32次方,也就是4GB,可是這4GB並非都給SQL Server使用的,默認狀況下是用戶態2GB,核心態2GB,因此說對於32位的系統SQL Server只有2GB的內存可供使用。不過能夠經過設置/3GB boot.int參數,來調整系統的配置,使用戶態爲3GB,核心態爲1GB。或者開啓AWE(地址空間擴展),將尋址空間擴展爲64GB,不過該設置有缺陷,下面會分析。數據結構

Physical Memory(物理內存):也就是一般所說的電腦的內存大小。併發

Reserved Memory(保留地址):應用程序訪問內存的方式之一,先保留(Reserve)一塊內存地址空間,留着未來使用(SQL Server中的數據頁面使用的內存就是經過這個方式申請  的)。被保留的地址空間,不能被其餘程序訪問,否則會出現訪問越界的報錯提示。編輯器

Committed Memory(提交內存):將保留(Reserve)的內存頁面正式提交(Commit)使用。高併發

Shared Memory(共享內存):對一個以上進程可見的內存。性能

Private Bytes(私有內存):某進程提交的地址空間中,非共享的部分。

Working Set:進程的地址空間中存放在物理內存中的部分。

Page Fault(頁面訪問錯誤):訪問在虛擬地址空間,但不存在於Working Set中會發生Page Fault。這個又分兩種狀況,第一種是目標頁面在硬盤上,這鐘訪問會帶來硬盤讀寫,這種稱爲Hard Fault。另一種是目標頁面在物理內存中,可是不是該進程的Working Set下,Windows只須要從新定向一下,成爲Soft Fault。因爲Soft Hard不帶來硬盤讀寫,對系統的性能影響很小,所以管理員關心的是Hard Fault。

System Working Set:Windows系統的Working Set。

二、Windows的內存檢測

能夠經過Windows的性能監視器來檢測Windows的內存使用狀況,如何使用性能監視器,能夠看這篇文章《使用「性能監視器」監視系統性能/運行狀況》 。在檢測內存上,比較重要的計數器有下面一些:

分析Windows系統的內存整體使用狀況的計數器:

Memory:Available MBytes:系統中空閒的物理內存數。

 

Memory:Pages/Sec:因爲Hard Page的發生,每秒鐘從硬盤中讀取或者寫入的頁面數。該計數器等於Memory:Pages Input/Sec與Memory:Pages Output/Sec之和。
分析Windows系統自身的內存使用狀況的計數器:

Memory:Cache Bytes:系統的Working Set,也就是Windows系統使用的物理內存數。

 

對於每一個進程的內存使用狀況的計數器:

Process:Private Bytes:進程提交的地址空間中非共享的部分。

 

Process:Working Set:進程的地址空間中存放在物理內存中的那部分。

從這些計數器中,咱們能夠看到系統中是否還有空閒內存,哪一個進程使用的內存最多,在發生問題的時候是否有內存使用量突變等狀況。這爲接下來分析SQL Server的使用提供一個前提條件。

2、SQL Server內部的內存管理

一、內存使用分類

按用途分類

1)Database cache(數據頁面)。SQL Server中的頁面都是以8KB爲一個頁面存儲的。當SQL Server須要用到某個頁面時,它會將該頁面讀到內存中,使用完後會緩存在內存中。在內存沒有壓力的狀況下,SQL Server不會將頁面從內存中刪除。若是SQL Server感受到內存的壓力時,會將最長時間沒有使用的頁面從內存中刪除來空出內存。

2)各種Consumer(功能組件)

 

Connection的鏈接信息

General:一組大雜燴。語句的編譯、範式化、每一個鎖數據結構、事務上下文、表格和索引的元數據等

Query Plan:語句和存儲過程的執行計劃。和Database cache相似,SQL Server也會將執行計劃緩存以供未來使用,減小編譯時間。

 

Optimizer:生成執行計劃的過程當中消耗的內存。

Utilities:像BCP、Log Manager、Backup等比較特殊的操做消耗的內存。

3)線程內存:存放進程內每一個線程的數據結構和相關信息消耗的內存,每一個線程需0.5MB的內存。

4)第三方代碼消耗的內存:SQL Server的進程裏,會運行一些非SQL Server自身的代碼。例如:用戶定義的CLR或Extended Stored Procedure代碼。

按申請方式分類

 

1)預先Reserve一塊大的內存,而後在使用的時候一塊一塊的Commit。Database Page是按這種方式申請的。

2)直接用Commit方式申請的內存,成爲Stolen方式。除了Database Page以外其餘內存基本都是按這種方式申請的。

 

按申請內存的大小分類

1)申請小於等於8KB爲一個單位的內存,這些內存稱爲Buffer Pool

 

2)申請大於8KB爲一個單位的內存,這些內存稱爲Multi-Page(或MemToLeave)

 

SQL Server對於Database Page都是採用先Reserved後Commit的方式申請的,而數據頁都是以8KB爲單位進行申請的。

對於Consumer中的內存申請,通常都是按Stolen方式申請的,且大多數的執行計劃的大小都是小於8KB的,少數特別複雜的存儲過程的執行計劃會超過8KB,默認的鏈接的數據包是4KB,除非客戶端特別設置了超過8KB(不建議)

第三方代碼的內存申請通常是按Stolen方式申請的,個別好比CLR中可能會用Reserved/Commit的方式申請。

線程的內存每一個都以0.5MB的方式申請,天然是放在MemToLeave中。

之因此花了這麼大篇幅來說SQL Server的內存分類,是由於SQL Server尤爲是32位的SQL Server對不一樣種類的內存的申請大小是不同的,對Commit、Stolen和MemTOLeave等類型的內存是有限制的。所以會出現系統中還有空閒內存,可是SQL Server不會申請使用的現象。

二、各部份內存的大小限制

 

1)32位的Windows

 

在SQL Server啓動時,會預先分配好MemToLeave區域的大小。默認大小爲256MB+256(SQL Server配置的容許最大線程數)* 0.5MB=384MB,所以Buffer Pool中的最大值爲2GB-384MB=1.664G。若是使用了AWE技術,能夠將系統的擴展地址空間達到64GB,但因爲AWE擴展出來的地址只能用Reserved/Commit方式申請,爲此MemToLeave的內存仍是384MB,Buffer Pool中的Stolen的最大內存爲1.664G,剩餘的內存均可覺得Database Page頁面使用。

2)64位的Windows

32位的SQL Server。因爲64位的操做系統,核心態再也不佔用32位進程的虛擬地址空間,所以MemToLeave的大小仍是爲384MB,Buffer Pool能夠達到3.664G。若是還開啓了AWE,這3.664GB能夠所有用於Buffer Pool中的Stolen,剩餘的內存均可以給Database Page頁面使用。不過這種狀況不多見,哪裏用64位操做系統的機器裝32位的哦-_- 。

64位的SQL Server。全部的內存都無限申請的,有須要就申請。

 

三、SQL Server內存使用狀況的分析

通常來講有兩種方式,第一種就是用來分析系統內存狀況時使用的用性能計數器來分析,第二種是使用動態管理視圖(DMV,只適用於SQL Server2005和2008)

1)SQL Server性能計數器

SQLServer:Memory Manager:Total Server Memory(KB):SQL Server緩衝區提交的內存。不是SQL Server總的使用內存,只是Buffer Pool中的大小。

SQLServer:Memory Manager:Target Server Memory(KB):服務器可供SQL Server使用的內存量。通常是由SQL Server能訪問到的內存量和SQL Server的sp_Configure配置中的Max Server Memory值中的較小值算得。

 

SQLServer:Memory Manger:Memory Grants Pending:等待內存受權的進程總數。若是該值不爲0,說明當前有用戶的內存申請因爲內存壓力被延遲,這意味着比較嚴重的內存瓶頸。

SQLServer:Buffer Manager:Buffer Cache Hit Ratio:數據從緩衝區中找到而不須要從硬盤中去取的百分比。SQL Server在運行一段時間後,該比率的變化應該很小,並且都應該在98%以上,若是在95%如下,說明有內存不足的問題。

SQLServer:Buffer Manager:Lazy Writes/Sec:每秒鐘被惰性編輯器(Lazy writer)寫入的緩衝數。當SQL Server感受到內存壓力的時候,會將最久沒有使用的數據頁面和執行計劃從緩衝池中清理掉,作這個動做的就是Lazy Writer。
 Page Life Expectancy:頁面不被引用後,在緩衝池中停留的秒數。在內存沒有壓力的狀況下,頁面會一直待在緩衝池中,Page Life Expectancy會維持在一個比較高的值,若是有內存壓力時,Page Life Expectancy會降低。因此若是Page Life Expectancy不能維持在一個值上,就表明SQLServer有內存瓶頸。 
 SQLServer:Buffer Manager:Database Pages :就是Database Cache的大小。
 SQLServer:Buffer Manager:Free Pages:SQL Server中空閒可用的大小。

 

SQLServer:Buffer Manager:Stolen Pages:Buffer Pool中Stolen的大小。

SQLServer:Buffer Manager:Total Pages:Buffer Pool的總大小(等於Database Pages+Free Pages+Stolen Pages)。該值乘以8KB,應該等於Memory Manager:Total Server Memory的值。

從上面這些計數器中咱們就能瞭解SQL Server的內存使用狀況,結合前面說的系統層的計數器大概能看出是否存在內存瓶頸。

 

2)內存動態管理視圖

在SQL Server 2005之後,SQL Server的內存管理是使用Memory Clerk的方式統一管理。全部的SQL Server的內存的申請或釋放,都須要經過它們的Clerk,SQL Server也經過這些Clerk的協調來知足不一樣需求。經過查詢這些DMV,能夠獲得比用性能計數器更加詳細的內存使用狀況。

咱們能夠經過下面的查詢語句來檢測SQL Server的Clerk的內存使用狀況。

使用sys.dm_os_memory_clerks查看內存使用狀況

  1. SELECT type, --Clerk的類型  
  2.     sum(virtual_memory_reserved_kb) as vm_Reserved_kb, -- 保留的內存  
  3.     sum(virtual_memory_committed_kb) as vm_Committed_kb, --提交的內存  
  4.     sum(awe_allocated_kb) as awe_Allocated_kb, -- 開啓AWE後使用的內存  
  5.     sum(shared_memory_reserved_kb) as sm_Reserved_kb, -- 共享的保留內存  
  6.     sum(shared_memory_committed_kb) as sm_Committed_kb, -- 共享的提交內存  
  7.     sum(single_pages_kb) as SinlgePage_kb, -- Buffer Pool中的Stolen的內存  
  8.     sum(multi_pages_kb) as MultiPage_kb -- MemToLeave的內存  
  9. FROM sys.dm_os_memory_clerks   
  10. GROUP BY type  
  11. ORDER BY type 

從上面的查詢語句,咱們能夠算出前面提到的內存大小

  1. Reserved/Commit = sum(virtual_memory_reserved_kb) / sum(virtual_memory_committed_kb)  
  2. Stolen = sum(single_pages_kb) + sum(multi_pages_kb)  
  3. Buffer Pool = sum(virtual_memory_committed_kb) + sum(single_pages_kb)  
  4. MemToLeave = sum(multi_pages_kb) 

經過上面的介紹咱們能夠知道SQL Server整體和各部份內存的使用狀況,若是我想知道數據頁的緩存中到底緩存了哪些數據,這些數據是屬於哪一個數據庫的哪一個表中的呢?執行計劃又是緩存了哪些語句的執行計劃呢?這也能夠經過DMV查看的到。

查看內存中的數據頁面緩存的是哪一個數據庫的哪一個表格的數據

 

  1. declare @name nvarchar(100)  
  2. declare @cmd nvarchar(1000)  
  3. declare dbnames cursor for 
  4. select name from master.dbo.sysdatabases  
  5. open dbnames  
  6. fetch next from dbnames into @name 
  7. while @@fetch_status = 0  
  8. begin 
  9. set @cmd = 'select b.database_id, db=db_name(b.database_id),p.object_id,p.index_id,buffer_count=count(*) from '   
  10. --這裏的object_id表明是SQL Server中的對象號,index_id表明是索引號,buffer_count表明的是頁面數  
  11. + @name + '.sys.allocation_units a, ' 
  12. + @name + '.sys.dm_os_buffer_descriptors b, ' + @name + '.sys.partitions p  
  13. where a.allocation_unit_id = b.allocation_unit_id  
  14. and a.container_id = p.hobt_id  
  15. and b.database_id = db_id(''' + @name + ''')  
  16. group by b.database_id,p.object_id, p.index_id  
  17. order by b.database_id, buffer_count desc'   
  18. exec (@cmd)  
  19. fetch next from dbnames into @name 
  20. end 
  21. close dbnames  
  22. deallocate dbnames  
  23. go 

-- 根據上面取出來的@object_id找出是哪一個數據庫的哪一個表

  1. SELECT    s.name AS table_schema, o.name as table_name --使用的就是table_schema.table_name表  
  2. FROM    sys.sysobjects AS o INNER JOIN 
  3.           sys.schemas AS s ON o.uid = s.schema_id  
  4. WHERE    (o.id = @object_id) 

-- 根據上面取出來的@object_id和@index_id找出索引的名稱

  1. SELECT    id, indid, name as index_name -- index_name就是索引的名稱  
  2. FROM    sys.sysindexes  
  3. WHERE    (id = @object_id) AND (indid = @index_id) 

-- 根據上面取出來的表名table_schema.table_name和索引的名稱index_name,還能夠找出該索引是創建在哪些字段上的

  1. EXEC sp_helpindex 'table_schema.table_name' 

查看內存中緩存的執行計劃,以及執行計劃對應的語句:

-- 輸出可能較大,請當心使用

 

  1. SELECT    usecounts, refcounts, size_in_bytes, cacheobjtype, objtype, text   
  2. FROM    sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_sql_text(plan_handle)   
  3. ORDER BY objtype DESC 

寫了這麼多居然發現大多數講的仍是數據收集的這一部分,相應的解決辦法尚未講到。。。因爲文章太長,具體的解決方法將在下一篇講解,下一篇將從Database Page、Stolen和Multi-Page三部分的具體瓶頸來說解。

原文連接:http://www.cnblogs.com/caspnet/archive/2011/02/21/1959539.html

相關文章
相關標籤/搜索