SQL Server內存

背景

最近一個客戶找到我說是全部的SQL Server 服務器的內存都被用光了,而後截圖給我看了一臺服務器的任務管理器。如圖算法

這裏要說明一下任務管理器不會完整的告訴真的內存或者CPU的使用狀況,也就是說這裏只能獲得非精確的信息,有可能就是一個假警報。sql

爲了讓個人客戶放心,我檢查了服務器而且查看了不少性能指標。我所看到的就是CPU和硬盤使用都是很低的只有內存是高的,這偏偏是咱們指望的SQLServer 服務器的狀態。SQL Server會盡量的使用內存,經過緩存儘量多的磁盤來改善性能。固然若是OS須要它也會當即釋放資源回來。數據庫

SQL Server 對內存是「貪得無厭」的,它會持有全部分配給它的內存,不管是否使用。而這也是咱們想要它去作的。由於它會存儲數據和執行計劃在緩存中,而後當使用完這些內存時,它不會釋放這些內存,緩存到內存中,除非兩種狀況纔會釋放緩存的數據內存:1) SQL Server 重啓或者內存不足 2) 操做系統須要內存 
默認的內存設定就是使用全部內存(安裝時設置),當操做系統須要內存時,它也會大量釋放內存。而後等到有內存時在從新大量持有。可是這種不是最佳實踐,最好仍是設定一個最大內存限制,這樣操做系統就會保證必定量的內存永遠爲SQL Server 使用。緩存

 

當看到資源管理器,Available MB 的內存有兩部分組成Standby--備用和Free--可用,這Standby 的空間系統已經把它緩存了,而Free的內存意味着沒有被使用。它們都叫作可利用內存。所以針對一開始那個客戶擔心咱們大可沒必要太擔憂。固然咱們還須要健康其餘的性能計數器,查明是否存在內存影響性能的隱患。須要關注的指標以下:服務器

  • Page Life Expectancy
  • Available Bytes
  • Buffer Cache Hit Ratio
  • Target & Total Server Memory
  • Memory Grants Pending
  • Pages/sec (Hard Page Faults)
  • Batch Requests/sec & Compilations/sec

介紹下這些性能參數:sqlserver

Page Life Expectancy (PLE)

這個性能計數器記錄了數據頁(非鎖定)在緩衝池中的平均時間。在生產高峯這個數值可能比較低,可是通常要保持這個數據在300s以上,數據待在緩衝中時間越長,那麼SQL的IO操做越少。性能

若是長期這個數值在300s如下,能夠考慮增長內存,固然因爲如今內存愈來愈大,這個值也變得不那麼重要了,可是對於中小系統依然能夠做爲一個標準閾值。優化

因爲這個閾值基於32位系統的4G內存,那麼標準算法能夠大體能夠推算:內存大小(GB)/4*300spa

也可使用下面的語句來查詢該計數器:操作系統

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%Buffer Manager%' AND [counter_name] = 'Page life expectancy'

Available MBytes

該計數器監測還有多少可用內存,是否操做系統存在內存壓力。通常咱們調查是否這個計數器持續在500MB如下,這說明內存太低。若是持續低於500則說明你須要增長更多的內存。

這個計數器不能經過T-SQL查詢,只能經過性能監視器觀察。

Buffer Cache Hit Ratio

緩衝命中率,這個計數器記錄平均多少頻率從緩衝池中取得數據。咱們在OLTP數據庫中通常這個比率是90%-95%(該數值經由@MSSQL123 指出發現是錯誤的,再次進行修改)。因爲sqlserver 把預讀也做爲緩衝比例,因此致使該值很高,因此該計數器只作理解,不能做爲真實性能瓶頸參考了。若是該計數器持續低於90%,則須要增長內存。

在可使用下面的T-SQL語句查詢:

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%Buffer Manager%' AND [counter_name] = 'Buffer cache hit ratio'

Target & Total Server Memory

服務器當前總內存(buffer)以及目標內存,在緩衝池初始化增長內存的時候,總內存會比目標內存稍低一點。這個比例會逐漸接近1,若是總內存沒有增加很快,就會顯著低於目標內存,這就表示以下兩點:

1)  你能夠分配儘量多的內存,SQL能緩存整個數據庫到內存中,而後若是數據庫小於機器內存,內存不會徹底用光,在這種狀況下,總內存將永遠小於目標內存。

2)  SQL不能增長緩衝池,好比系統內存有壓力。若是這種狀況你須要增長最大服務器內存,或者增長內存來改善性能。

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%Memory Manager%' AND [counter_name] IN ('Total Server Memory (KB)','Target Server Memory (KB)')

Memory Grants Pending

這個計數器測量等待內存授予的SQL的進程數量。通常推薦閾值爲1或者更少。若是大於1這說明內存不足按順序等待內存釋放再操做SQL。

通常工做中出現這種等待多是因爲糟糕的查詢,缺失索引,排序或者哈希引發的。爲了查明緣由能夠查詢DMV --sys.dm_exec_query_memory_grants 這個視圖,將會展現哪個查詢須要內存授予執行。

若是不是以上緣由引發的內存等待,則須要增長內存來解決這個問題。此時就有理由增長硬件了。查詢的T-SQL語句以下:

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%Memory Manager%' AND [counter_name] = 'Memory Grants Pending'

Pages/sec (Hard Page Faults)

這裏也使用數據庫級別計數器:當須要讀取或寫入的頁不在內存中,須要到磁盤中讀取時計數。這個計數器是一個記錄讀和寫的總和而且不能直接在內存中獲取只能從因盤中讀取(致使resulting in hard page faults),這個問題是因爲操做系統必須交換文件在磁盤上,當訪問內存時,內存不足則須要交換文件到磁盤上,因爲磁盤讀寫速度遠低於內存,性能就會受到嚴重影響。

對於這個計數器,推薦閾值爲<50(或者某個穩定值),若是看到高於這個值,不過須要注意,只要這個值可以穩定在一個較低的水平,沒有持續性的大批量數據的寫入(磁盤)於讀取(從磁盤載入內存),均可以接受。相反,若是長期在一個高位水平,而且觀察到PLE不能穩定在參考值範圍內,說明內存可能存在瓶頸。固然,若是數據庫備份或者還原,包括導出、導入數據以及內存中映射文件等等這些也會致使性能計數器超出某個穩定值。

Batch Request & Compilations

該計數器包含兩個檢查

  • SQL Server: SQL Statistics – Batch Request/Sec.  傳入查詢的數量(批處理數量)
  • SQL Server: SQL Statistics - Compilations/Sec.  新創建的執行計劃數量

若是Compilations/sec是25%或者相對Batch Requests/sec更高,則執行計劃將被放到緩存中,可是永遠不會重用執行計劃。寶貴的內存就被浪費了,而不是緩存數據。這是糟糕的實踐,咱們要作的就是阻止這種狀況,

若是Compilation/sec 很高好比100,表示有大量的即席查詢正在運行。這時能夠啓用「optimize for ad hoc」把執行計劃緩存,可是隻有在第二次查詢時才能被使用。

使用以下T-SQL能夠獲得相應的指標:

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%SQL Statistics%' AND [counter_name] = 'Batch Requests/sec';

SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%SQL Statistics%' AND [counter_name] = 'SQL Compilations/sec';

一樣能夠得到比率:

SELECT ROUND (100.0 * (SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%SQL Statistics%' AND [counter_name] = 'SQL Compilations/sec') / (SELECT [cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%SQL Statistics%' AND [counter_name] = 'Batch Requests/sec') ,2) as [Ratio]

關於如何設定數據庫可用的內存最大值,如圖所示:

推薦閾值:通常來講,我都是採用10%用於操做系統其它90%分配給數據庫。固然若是內存很大能夠調整這個比例小於1/9,對於內存較小的一般我都預留4-6G左右給操做系統。

咱們看一下實際例子:

在性能監視器中看一下這個計數器,咱們能夠看到這個服務器處於健康狀態下,有11GB的可用空間,沒有PageFaults(I/O只從緩存中沒有交換到磁盤),緩衝的比率爲100%,PLE超過20000s,沒有內存等待,充足的總內存和較低的編譯比率(編譯數/查詢數).

這個測量數據很容易理解,這要比任務管理器更具備做用,能依據此作出判斷是否有足夠的內存在這臺SQL Server服務器上。

總結

    若是隻根據任務管理器來作出判斷,咱們很容易出現錯誤決定。由於無論系統多少內存,SQL Server 會盡量的使用佔用內存,這不是bug。緩存數據在內存中有很好的效果,意味着服務器是健康的,也爲用戶提供了更好的執行效率。在實際數據庫環境中,通常忽然遇到的性能問題多半是由於T-SQL語句引發的,就如我前面提到糟糕的查詢(缺失索引、排序、哈希等等),這個時候經過語句優化能夠很好的解決突發問題,這裏就不詳解了。若是服務器廣泛存在文章中出現的內存性能計數器問題,那就寫報告提交內存增長需求吧。

相關文章
相關標籤/搜索