total server memory 和 target server memory
因為lock pages 和沒有設置服務器最大內存導致系統不穩定
內存的分配和使用在網上一直是討論的話題。對sql server 來說使用了內存但是不釋放是很正常的事情,和其他的應用程序是不一樣的,導致一些用戶認為sql server確實內存但事實並非如此。
存儲引擎自調整
從sql server 2005開始,內存的管理就是動態的,與其他關系型數據庫不同使用已經調整好的內存空間。如plan cache 是全部的並且自動的,引擎控制根據當前數據庫的負載和其他活動信息來控制plan chache內存。sql server 雖然缺少內存的控制方法,但是還有有參數可以設置內存的,如操作系統的版本,內存的大小和處理器的體系結構。
sql server 是如何分配內存的
第一反應就是查看windows任務管理關於sql server 的內存使用情況,一看到sql server 占用了很大的內存就可能會認為sql server 缺少內存,但是缺少內存和占用很大內存其實是沒什么關系的。sql server是被設計為大內存使用的,如buffer cache,存放了大量的數據頁,為了減少io,提高性能。通常,不管你提供了多少內存sql server 都能使用光,除非你接到一個來自操作系統的memory low通知,sql server 就會自動調節減小內存,通知有2中:
memory high:通知sql server可以增加內存的使用量
memory low:通知sql server 釋放內存
如果windows 不通知,那么sql server 就不會增加或減少內存,在windows 2003 和 sql server 2005 以前的版本是沒有的。有一篇關於sqlos中內存的文章介紹了不同類型的內存壓力,大致如下:

文章地址:http://blogs.msdn.com/b/slavao/archive/2005/02/01/364523.aspx
sql server 最大內存使用量由以下幾點要素:
1.安裝的物理內存數量
2.操作系統的最大內存限制
3.sql server 體系結構,32b,64b
4.sql server 配置項
5.sql server 版本
32bit地址空間的限制
對於sql server 32位最大的影響就是32位的地址空間,也就是最大4g而且包含內核模式和用戶模式。用戶模式和內核模式各2個g。主要我們討論一下幾點
1.sql server 用戶模式如何分配內存
2.非buffer pool的保留空間
3.用戶模式使用3g 內存
4.sql server 如何使用大於4g內存,data cache調用awe內存。
接下來主要講的都是32bit 下內存使用的限制和64bit關系不大。
用戶模式vas分配和virtualalloc
sql server 為用戶默哀是保留了2g的內存地址,sql server 用戶模式需要內存時,通過調用virtualalloc 分配內存並返回32位的指針,因為地址空間的限制,所以sql server 只能使用2g內存。
通過virtualalloc分配的內存並不一定是實際的物理內存,不管安裝了多少物理內存,sqlserver都是2g的地址使用空間。windows也保證sql server 和其他應用程序使用的內存,不會超過實際物理內存和頁面文件的總容量。如果總共安裝的內存少於2g,那么sql server 就會又物理內存的限制,sql server buffer pool的內存也不會超過安裝的內存數量。virtualalloc 分配的內存都是頁模式的,也就是如果出現內存壓力windows 就可以直接把內存寫入到磁盤中。
非boffer pool 分配內存(保留內存)
如果sql server 請求大於8k的連續內存的時候,會使用多頁分配器分配內存。backup buffers 是非buffer pool分配的最大的一個,需要的內存是 maxtransfersize * backupbuffercount 在正常的備份下,需要16個backup buffer,每一個buffer又4m的內存。所以會吃掉64m的非buffer pool 內存。為了保證有住夠非buffer pool,32b的sql server 在啟動的時候會保留一部分內存。一旦有保留內存,那么buffer pool的內存空間會是安裝的空間減去保留的空間。對於2005和2008保留空間為 maxworkerthreads*0.5mb+256mb(默認保留空間大小),maxworkerthreads = (processprcount-4)+256。在2000 中maxworkerthreads = 256,按這個計算保留空間至少是384MB,但是通常少於432mb。保留空間的參數在sql server 啟動參數內設置,標記為-g,可是適當在計算出來的結果上增加內存。sql server 一共2g的地址空間減去保留的,大概剩下1.6G供buffer pool 使用。對於超過4gb的內存可以使用awe來分配內存。
VAS調整
對於4g的內存,系統可以修改內核的地址空間使用率把1:1,變為1:3。這個叫做4g調整,這樣就減少了內核模式下的地址空間,導致了PTE減小,pte是虛擬內存和物理內存的映射,一但減小,sql server 總共可使用的內存也就背減少了。所以在調整的時候要謹慎。在windows 2008下可以使用bcdedit /set 命令設置increaseuserva 可以設置從 2048 到 3072的值。在2000 到 2003 可以使用/3g的標簽來開啟。
AWE
如果安裝了超過了4個的內存,那么就可以使用awe,當然windows 必須支持才能使用。開啟pae,系統最多能夠使用64G內存。在內存分配上因為使用virtualalloc分配內存會有限制,那么就改用allocateuserphysicalpage來分配內存,一旦被分配那么內存頁被鎖住,無法交換到交換文件。當啟用awe后所有的datacache使用過awe分配內存還有就是 plancache也是。要啟用awe那么pae就必須被設置,還有在sql server 的awe enabled 參數sql server 的啟動用戶必須有lock pages 權限。因為awe內存無法被交換出去,所以設置最大內存數量很偶必要,使得sql server 內存使用量得到限制,不會無限期的增長影響其他應用程序和系統內存的使用問題。在系統中如果你的內存少於16g,你可以使用前面提到的awe+4gt的方式,但是不推薦因為如果你一旦設置了4gt,windows 可管理內存從64g下降到了16g yinwei 4gt減少了pte的大小。
啟動參數-g
在sql server 啟動的時候會分配一部分保留內存,保留內存對buffer pool 來說是比較小的。很多的內存是從buffer pool上分配而不是從保留空間中分配,因此基本上不會有問題,但是隨着日積月累應用程序變的越來越復雜,默認的保留空間已經無法滿足需求那么就通過-g參數配置。因為不合適的空間大小和保留空間的碎片問題,導致無法請求到連續的內存空間。查看sys.dm_os_virual_address_dump 動態性能視圖可以查看可用的虛擬地址空間。關於確定可用地址空間可以看相關文章:http://sqlblogcasts.com/blogs/christian/archive/2008/01/07/sql-servermemtoleave-vas-and-64-bit.aspx
保留空間的碎片問題是最難處理的,如果你打電話到微軟技術支持,他們給的建議就是升級到64b,因為64b的虛擬地址空間是8t,不會不夠如果你不想那么就加大你的保留空間地址。
診斷內存壓力
當sql server 內存不足的時候,那么data cache 存儲的數據就少,查詢不能在內存中請求到數據,那么就請求io,放入內存,這些數據又很快的被清出內存,需要的時候有繼續從io讀進來,這個就是buffer pool 滾筒。buffer pool 滾筒會照成io過高,就會誤認為是io的問題,其實是內存不足的問題。
內存相關計數器
有一些重要等待和內存使用率相關的性能計數器,但是要記清楚並沒有一個計數器就能夠表明內存壓力的,一個簡單的計數器快照並不能說明問題。內存壓力的診斷需要一段時間的跟蹤。
SQL Server :Buffer Manager
又很多有用的計數器都是這 buffer manager 對象下面,可以幫助發現buffer pool滾筒的問題。
buffer cache hit ratio
buffer cache hit ratio一般情況下在oltp中要高於95%,在olap中要高於90%。可惜的是沒有關於這個性能指標相關的解釋,和這個值是如何影響預讀機制的。如果這個指標的值有巨大的下降那么就說明有問題。這個不能說明內存壓力和sql server 健康指數。
page life expectancy
page life expectancy是頁生命周期,也就是一個數據頁在內存中的時間。在以前sql server 2000 4g的內存已經很大了,sql server buffer pool的大小是1.6g,如果sql server 從磁盤上讀取1.6g的數據也只要5分鍾,但是今天64g的內存是主流,如果從磁盤一下子讀取50g的內存,會嚴重的沖擊io。當存在大量的查詢掃描表,讀入新的數據頁,導致生命周期值下降也不是不正常的。這個值必須長期的監視來分析問題。
Free Pages
free pages是內存中空頁的數量,不要接近於0。這個值說明查詢能否在其他查詢不是放內存的情況下,快速的分配內存的主要依據。如果free pages 很少,頁生命周期很短,並且伴隨着空頁爭用(free list stalls/sec)的情況那么很有可能導致內存壓力。
Free list stalls/sec
Free list stalls/sec每秒空頁等待的數量,如果一段時間內都在0以上那么說明可能存在內存壓力。
lazy write/sec
lazy write/sec 就是每秒寫入磁盤的次數。如果發生量很大並且生命周期很短,free page 很少,但是 free list stall/sec 量很大,那么就是發生內存壓力了。
SQL Server:memory Manager
SQL Server:memory Manager對象內對內存的消費和內存管理的問題提供了很重要參考
total server memory 和 target server memory
這2個計數器代表了當前sql server 使用的總共內存和sql server 想要用的內存。如果 target server memory超過了total server memory,也是內存壓力的重要標志。sql server 會減少內存的需求來接近服務的可用內存,或者通過最大服務器內存配置,所以當內存出現壓力問題的時候不應該第一時間去查看這2個計數器
memory grants outstanding
該值是現實多少進程已經成功的獲取了內存的授權。在一段時間內,業務高峰期,如果該值過低,那么標志可能存在內存壓力,特別是 memory grants pending 也比較高的情況下。
memory grants pending
該值是有過少進程正在等待內存的授權。如果為非0,那么說明需要調整或者優化負載或者增加內存。
內存相關的DMV
和內存相關的等待和非buffer pool 內存分配的信息,從dmv中獲取。
sys.dm_exec_query_memory_grants 可以查看正在等待授權的查詢,特別是大內存的授權
sys.dm_os_memory_cache_counter multi_pages_kb 顯示了多頁分配的內存分配
sys.dm_os_sys_memory 合計了系統當前內存,緩沖,cache,多頁分配分配的內存。
sys.dm_os_memory_clerks 顯示相關管理內存的書記進程,如 buffer pool 大內存的使用並且結合 MEMORYCLERK_SQLQERESERVATIONS 可以發現buffer pool 內存不住
內存相關問題
通常的一些問題可以被分為3種:錯覺,錯誤配置,正在的問題。大量的疑似內存問題的最后其實只有一小部分才是真正的問題。
分頁問題
當sql server 重要的組件被page out了,會在error log 中出現一個信息“a significant part of SQL Server process memory has been paged out”對於 workset的trim通常是下列的情況:
1.當沒啟用lock pages的時候,不正確的最大服務器內存的設置
2.windows 中系統緩沖,被用來處理非緩存的io操作,如復制文件。
3.硬件驅動問題導出使用過多的內存。
最有效的阻止方法是,開啟lock pages,文章:http://support.microsoft.com/kb/918483講述了64b sql server 發生workset trim的根本原因。
因為lock pages 和沒有設置服務器最大內存導致系統不穩定
如果sql server開啟了 lock pages 但是 最大服務服務內存又沒設置,sql server 會吃光所有的服務器的可用內存。當windows 內存緊張會向通知sql server 內存壓力,但是buffer pool 和 working set 都不會被交換頁面文件。這樣會導致windows crash。如果最大內存數設置的過大也會造成同樣的情況。
701錯誤和 FAILED_VIRTUAL_RESERVE
當sql server 申請一個連續的vas失敗,就會返回701錯誤和答應出需求大小的信息。這個錯誤只會發生在32b的sql server,32b sql server vas十分有限。這個錯誤和buffer pool 沒有什么關系主要是大於8k內存分配的時候出現。解決辦法就是使用-g啟動參數,修改sql server保留空間。
多實例下的內存設置
sql server 如果多實例安裝在單個機器上或者一個故障轉移能減少license的購買。當一台服務器上有多個實例,那么設置min_server_memory 和max_server_memory 很重要,根據每個實例的負載,避免出現內存沖突的情況。根據先前提到過的性能指標和dmv 對內存使用情況監測,設置一個合理的最大內存和最小內存數。在多實例情況下,建議把最小內存數也設置上,因為如果有最小內存數,那么sql server 申請內存的時間會減少。如果最小內存數沒有設置,sql server 可能會自願減少內存的使用率而導致性能下降。
總結
在內存上面 32b 和64b 又很大的不同,如果負載較高那么就是用64b,6號那天sql server 2012發布,還沒去看聯機文檔,但是聽朋友說2012的32b不在支持awe,也就是說如果大內存那么就用64b。64b內存方面很有優勢。這篇主要講了內存的狀況,總結到這里我已經明顯的感覺到,常見問題遠沒有原理來的重要。troubleshooting只是原理的一種應用而已。關於資源的都講完了,cpu,內存,io,下一篇會講講miss index,miss index 也是會引起 cpu,內存,io 的異常狀況。
