在數據庫服務器中,內存是數據庫對外提供服務最重要的資源之一,
不只僅是Sql Server,包括其餘數據庫,好比Oracle,MySQL等,都是一類很是喜歡內存的應用.
在Sql Server服務器中,最理想的狀況是Sql Server把全部所需的數據所有緩存到內存中,可是這每每也是不現實的,由於數據每每老是大於可用的物理內存
能夠說內存是否存在壓力可以直接決定數據庫可否高效運行,
同時,若是內存出現壓力,同時也會影響到CPU的使用和存儲性能,能夠說是一損俱損,具備連帶性。
那麼,如何識別內存是否存在壓力,如何判斷一臺服務器上是否存在內存瓶頸?html
Sql Server 2012以後,對內存的管理進行了大刀闊斧的改革,全部的內存管理都受Max Server Memory的控制
以下截圖所示的最大服務器內存設置(固然這個截圖是我本機上一個測試實例,這裏並不說明內存該怎麼配置)
算法
而大多數的內存量化都涉及到Sql Server的Buffer Pool,一個內部的緩存管理器,sql
/*
20160525補充:
Sql Server 2012以前的版本,
對於Buffer Pool是存儲Data Cache的,
另一部分專用的內存稱之爲Memory To Leave(Sql Server 2012以後,叫作Stolen Memory),
這部份內存的使用也是一個很是大的話題,這裏暫不展開論述。
32位操做系統下,這部份內存是Sql Server 啓動後直接初始化分配的,64位操做系統是直接跟操做系統申請,
若是須要的Stolen Memory過大,一樣會「擠壓」Buffer Pool的內存
*/數據庫
可是,Sql Server2012以後,全部內存的管理都受到Max Server Memory的控制。
同時,Sql Server在運行的過程當中,會將各類內存的參數狀況記錄下來,這對咱們去判斷Sql Server內存壓力有着很是重要的參考意義
下面提到的部分計數器的就存儲在sys.dm_os_performance_counters這個系統視圖中windows
咱們抽取其中最重要的幾個來作解釋說明:緩存
須要注意的是,不能經過上述某一個值就武斷地判定內存瓶頸,各個計數器之間是有必定的關係的,要結合多個值來作謹慎的分析判斷。服務器
Page Life Expectancy又簡稱位PLE,含義是內存頁面在內存中停留的平均時間,是內存壓力判斷的一個重要參考值
在系統視圖sys.dm_os_performance_counters中能夠查到,單位是秒.
須要注意的是它不是指某一個page的最大值或者最小值,而是全部由全部頁面停留在buffer pool中的時間計算出來的一個平均值
若是這個值越大,說明Sql Server在檢索數據時候直接從buffer pool中獲取數據的機率越大,
若是Sql Server直接從buffer pool中檢索到數據,那麼就不用去磁盤中去查詢,由於直接從內存中獲取數據的效率要遠遠高出從磁盤中去獲取數據
由於從內存中查詢數據的延遲是納秒級的,而從磁盤獲取數據的延遲是毫秒級的,這之間差了兩個數量級,
可見從緩存中獲取數據和從磁盤中獲取數據,對性能的影響有多大
那麼PLE這個值多少位正常呢?我發現不少資料上多這個值都有誤解,說是300S,300S是在十多年前的一個參考值,
是基於當時的服務器內存受到4GB內存的限制的影響獲得的,
目前服務器內存動輒超過100GB的狀況下,用一樣的標準,顯然是不夠準確的,這個值的計算是跟具體的服務器內存配置有關的
具體我就不作進一步的解釋,能夠參考以下連接sqlserver
https://simplesqlserver.com/2013/08/19/fixing-page-life-expectancy-ple/性能
一個可供參考的標準算法是 Max Buffer Pool(GB)/4*300(S)
這個值能夠經過sys.dm_os_performance_counters 這個系統視圖直接查詢得出學習
select * from sys.dm_os_performance_counters where object_name like '%Buffer Manager%' and counter_name='Page life expectancy'
好比你的服務內存是64G,分配給Sql Server最大內存(上述Max Server Memory)是60G
那麼PLE的參考值就是60/4*300=4500S,大概是75分鐘,也就是說,最低限度是每75分鐘,內存中的數據跟磁盤作一次完整的交換
若是你的服務器上的PLE值長期低於計算出來的這個參考值,或者這個值在某個時間段內有很是明顯的變化,那麼你就須要注意內存是否存在瓶頸了
若是你真的作過這方面觀察的話,這個值在不一樣環境中差異是很是大的
固然對於測試服務器,常常沒幾我的用,或者壓力很是小的服務器,內存沒壓力或者服務器根本沒有負載的狀況下,緩存進去的數據可能就一直存在於內存中
這個值有可能很是大,達到幾萬秒都是有可能的
不信我給你截個圖,呵呵
固然對於壓力比較大的生產服務器,即使是有幾十個GB的內存,這個值,也有可能小到幾十秒鐘,我所在的公司就是這個狀況。
因此,PLE的值是做爲判斷內存是否存在瓶頸的最重要的指標之一。
Buffer Cache hit ratio就是緩存命中率,字面上的解釋就是一個查詢過程當中所須要的時候,直接從內存中讀取出來的比例佔全部數據的百分比
鑑於表現出來的值受到其算法的制約,反卻是在內存壓力診斷的時候並不具有太多的參考意義,
既然Buffer Cache hit ratio不具有太多的參考意思,那麼爲何把他放在這裏呢?
由於這一個很是流行的參數,不少材料上都提到過這個參數
不少材料上都介紹其閾值是90%,95%之類的參考值,其實都是錯誤的,
其實真正觀察過的人,以下連接,早就有人有此疑問了,從PLE和Buffer hit ratio得出根本不一致的結論,
有時候咱們作學問仍是要講究嚴禁的,不能人云亦云
怎樣理解Buffer hit ratio 是99%, 但Page life expectancy<200?
我這裏不作詳述,能夠參考個人另外一篇博文,裏面有詳述。http://www.cnblogs.com/wy123/p/5272675.html
另外,真的很佩服老外,從本質上闡述了Buffer Cache hit ratio,能把學問作的這麼認真,真的不容易。
經過sql查詢緩存命中率
SELECT CAST(CAST((a.cntr_value * 1.0 / b.cntr_value)*100 as int) AS VARCHAR(20)) as BufferCacheHitRatio FROM ( SELECT * FROM sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio' AND object_name = CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLServer:Buffer Manager' ELSE 'MSSQL$' + rtrim(@@SERVICENAME) + ':Buffer Manager' END ) a CROSS JOIN ( SELECT * from sys.dm_os_performance_counters WHERE counter_name = 'Buffer cache hit ratio base' and object_name = CASE WHEN @@SERVICENAME = 'MSSQLSERVER' THEN 'SQLServer:Buffer Manager' ELSE 'MSSQL$' + rtrim(@@SERVICENAME) + ':Buffer Manager' END ) b
這兩個計數器分別是對應的平均每秒鐘的物理讀/寫的數據量,這個計數器的是一個累計值,單位爲page,而每一個page又是8Kb,
能夠換算成一個基於kb或者mb位單位數據
對於計數器中的相似累計值,並不妨礙咱們經過計算得出某個時間間隔內的平均值。
也就是說,
對於 Page reads / sec,一個查詢在執行過程當中,發現須要的數據不存在於buffer pool中,須要到磁盤上去查詢
對於 Page writes / sec ,就是在面臨內存壓力的時候,將內存頁寫入磁盤來騰出內存空間
上面說了,直接從buffer pool中,也就是內存中讀取數據和從磁盤中讀取數據的時間上的差異是巨大的,對性能的影響也是很是明顯的
實際中咱們也會常常遇到這種現象,有些SQL查詢語句,第一次執行比較慢,可是再次執行的時候,就相對快了不少,
固然經過set statistics io 這個信息也能發現有第一次存在物理讀的現象,這種速度上的差異,仍是比較明顯的
這兩個值能夠經過以下sql查詢獲得
select * from sys.dm_os_performance_counters where object_name like '%Buffer Manager%' and (counter_name='Page reads/sec' or counter_name='Page writes/sec' )
若是一臺服務器上常常發生大批量的物理性IO操做,你就要注意是否存在內存問題,
由於常常性的大批量的物理IO會嚴重拖慢SQL的執行效率,理想狀況下,這個值不該該過大,也有材料上說不能持續大於0,我我的以爲有點絕對了
其實也沒有一個絕對的標準,只要這個值可以穩定在一個較低的水平,沒有持續性的大批量數據的寫入(磁盤)於讀取(從磁盤載入內存),均可以接受
相反,若是長期在一個高位水平,而且觀察到PLE不能穩定在參考值範圍內,說明內存可能存在瓶頸。
Lazy writes 是每秒被緩衝區管理器的惰性編寫器(lazy writer)寫入的緩存區的數據page信息。
Lazy writer是一個系統進程,用於批量刷新內存中的髒頁到磁盤,而且將原來髒頁佔用的內存空間清理的一個動做。
若是存在內存壓力,Lazy writer會被觸發,將髒頁和長時間沒有用到的計劃緩存清理出內存,
若是常常被觸發,那麼說明內存可能存在瓶頸
須要注意的是,經過以下 sys.dm_os_performance_counters 查詢出來的Lazy writes/sec值是一個累計值
可是這也不妨礙咱們得出某一個時間間隔內發生的Lazy writes/sec的數據,相信聰明的你必定能夠算出來
select * from sys.dm_os_performance_counters where object_name like '%Buffer Manager%' and counter_name='Lazy writes/sec'
對於髒頁以及老化的緩存計劃,有其餘機制去實現寫入磁盤存儲並清理器佔用的內存空間
Lazy Write是在面臨內存壓力的狀況下觸發的,
若是某一個時間間隔內,Lazy Write持續不爲零,就要結合PLE以及Page reads(writes) / sec 來判斷分析內存是否存在不夠用的狀況了。
說完PLE和Page reads(writes) / sec 以及Lazy writes / sec以後,就能夠作一個小小的總結了
上面說了,衡量內存瓶頸的時候,一般要結合多個值來作出判斷,
若是你的PLE不在計算出來的參考值預期以內,同時又伴隨着大量的Page reads(writes) / sec
那麼就幾乎能夠判定你的服務器存在內存瓶頸了
由於PLE達不到預期值,也就是說可能有大量所須要的數據不存在於緩存中,
而去讀這些數據,又要進行從磁盤上的物理讀取,那麼就會出現Page reads(writes) / sec 較高的現象
物理讀取出來的數據要佔用緩存空間(以後才能返回給查詢的客戶端),
而原來緩存空間中的數據是經過Lazy writes被清理出內存,這樣數據從磁盤進入緩存,而緩存中的數據又被清理出去,形成的結果就是PLE上不去
因此結合這三個值的信息,基本上就能夠判定你的內存是否存在瓶頸。
固然除了上述三個計數器,還有其餘更多的信息去對內存作診斷,咱們繼續。
Total Server Memory是Sql Server內存管理器「已提交」內存,說白了就是已經佔用了的內存,
而Target Server Memory則是Sql Server內存管理器可用的最大內存
這兩個值也可用經過sys.dm_os_performance_counters 查詢出來
select * from sys.dm_os_performance_counters where object_name like '%Memory Manager%' and counter_name in ('Target Server Memory (KB)','Total Server Memory (KB)')
當Total Server Memory小於Target Server Memory的時候,Sql Server還知道系統還有可用內存,在須要內存中的時候,直接跟系統申請,
此時Total Server Memory會逐漸變大。
可是,當Total Server Memory接近於或者等於Target Server Memory的時候,Sql Server會意識到已經用完了系統的可用內存,
若是在須要內存的時候,系統已經沒法繼續分配新的內存,它就須要清理已用的內存空間,將新清理出來的空間給新的數據使用
這個彷佛又要跟上面說的PLE以及lazy write聯繫上了,
固然,系統內存空間每每是小於數據的空間的,好比有可能你的數據庫文件大小是500GB,而內存以後32G或者64G,
數據庫通過一段時間的運行後,Total Server Memory老是接近於或者等於Target Server Memory的,
那麼咱們說Total Server Memory和Target Server Memory的意義何在?
上面說了,鑑於數據文件中的數據每每都是大於可用物理內存的(固然極端例子也有,你數據庫只有2GB,內存32GB)
數據頗有可能不徹底都能緩存在內存中,可是最起碼,要緩存持續到必定時間再去釋放空間(給新的數據使用),而不是不停地直接去讀磁盤,這就要求有一個度
你不能說Total Server Memory老是接近於或者等於Target Server Memory,沒內存用了,清理內存是正常的
若是緩存75分鐘是正常的,
發現Total Server Memory持續性接近或者等於Target Server Memory,而PLE明顯低於計算出來的參考值,低到幾分鐘甚至一兩分鐘,
同時觀察到內存跟磁盤之間頻繁地、大量地物理性交換數據,這也說明,內存極有可能存在瓶頸。
Paging File也即緩存文件,另一個名字叫作虛擬內存,你必定據說過,就是用拿物理磁盤空間當作內存空間使用,
Windows系統的虛擬內存文件通常是存儲在C盤的,一個叫pagefile.sys的文件,默認是隱藏的
以下截圖
這裏先說明兩個問題:
1,Sql Server會用到緩存文件嗎?
答案是:會
2,Sql Server可否控制使用物理內存仍是page file?
答案是:不能,一個windows上的應用,使用物理內存仍是page file,是由操做系統決定的,應用程序自己沒法決定自身去使用哪一部份內存
那麼如何知道使用了多少緩存文件空間,經過sys.dm_os_sys_memory這個視圖能夠查詢出來。
固然我這個截圖是在我本機,看不出來有什麼特別大的使用了,一個字段是total_page_file_kb,一個是available_page_file_kb
顧名思義,總的減去可用的,就是已用的
那麼,文件緩存跟內存瓶頸有什麼關係呢?
應用程序對文件緩存的使用時不受自身因素控制的,徹底是由操做系統來決定的,Sql Sever也不例外,文件緩存使用的多少固然也是由操做系統來調度
文件緩存的使用多少能反映什麼?
若是說文件緩存使用的越多,從側面能夠反映出來服務器上當前物理內存和實際需求內存之間的差距,固然這個差距越大,說明內存缺少程度越高
文件緩存的使用是受到Windows操做系統調度的,這一點Sql Server沒法決定本身的緩存數據是存放在屋裏內存中或者是page file中,
這一點就是一個黑盒了,具體算法我無從得知
從實際測試來看,物理內存的消耗和page file的消耗是同步的,
舉個例子,執行一個很是大的查詢,經過 sys.dm_os_sys_memory能夠很是清楚地觀察到,
在消耗物理內存的同時,也伴隨着虛擬內存的消耗,這二者到底怎麼分配,或者這之間有什麼線性關係,我目前還不清楚,也但願有高人指點
能夠很明確地說,某些生產服務器,由於缺少物理內存,32GB的物理內存的機器,
對於文件緩存的使用達到了一個很是高的程度(30多個GB),超過了物理內存自己
這應該就是一種非正常狀態,不過這個值也沒有一個權威的數據,也但願有了解的能夠留言貢獻
固然獲取某些環境下有更大的文件緩存使用,我只是沒見過而已。
根據page file的使用狀況,發現若是大量使用page file,甚至超過了物理內存自己,
能夠大概瞭解到Sql Server服務器實際所需內存與現有內存的差別程度。
也能夠在進行內存瓶頸判斷的時候,做爲參考指標之一。
總結
林林總總闡述了上述幾個內存瓶頸壓力判斷指標,也僅僅是涉及到了一部分跟內存有關的計數器,固然包括但不限於上述幾個值。
若是作內存瓶頸判斷,能夠有更多的參考值,
前文也說了,內存壓力下,
Sql Server是一個具有自我調節(self tuning)的應用系統,各個計數值的值是具備一系列的相關性的,每每多個性能計數器會表現出來一些一致性的特徵
好比內存不足的狀況下:PLE上達不到預期值,Page reads(writes) / sec 又持續保持在一個較高的水平,同時伴隨着Lazy Writer / sec 持續性的發生
若是有更多的其它參考的判斷指標,固然更具有說服力
可是若是經過上述值,也能將內存的壓力是否存在瓶頸定位個八九不離十。
對於其餘的內存相關的計數器,有時間會繼續總結。
其實說了這麼些相關內容,也僅僅是對Sql Server內存一個作了一個很是粗略的分析,固然也能夠對各個部分的內存分類進行進一步細化的分析和論述。
本文粗淺第分析了判斷Sql Server內存瓶頸的一些知識點,尚有不足的地方還請指出,謝謝。但願可以幫到各位對Sql Server感興趣的看官,共同窗習。