SQLSERVER 里經常看到的CACHE STORES是神馬東東?
當我們在SSMS里執行下面的SQL語句清空SQLSERVER的緩存的時候,我們會在SQL ERRORLOG里看到一些信息
DBCC FREEPROCCACHE
大家可以看到cachestore、object plans、sql plan、bound tress等名詞
cachestore flush for the 'Object Plans' cachestore (part of plan cache) cachestore flush for the 'SQL Plans' cachestore (part of plan cache) cachestore flush for the 'Bound Trees' cachestore (part of plan cache)
那么這些名詞是什么意思呢?是什么功能組件呢?這篇文章為大家介紹SQLSERVER Buffer Pool,大家就會知道了
翻譯自:Bufferpool Performance Counters
原文大意
在網上有非常多的文章、博客、帖子介紹內存配置和內存的一些情況,但是依然給大家帶來了太多的誤解。
這些文章都有講到SQLSERVER 內存、虛擬內存、AWE功能還有其他的一些介紹我個人認為不能很好地對SQLSERVER內存方面的各個性能計數器有很好的理解
在這篇文章里,我會著重講解BufferPool的一些機制,例如你的數據頁面和索引頁面在SQLSERVER的內存里是怎麼存放的
在性能監視器里你能夠使用這些知識去判斷當前BufferPool的狀態。
(當我談論到頁面的時候,我只談論數據頁面和索引頁面。對于事務日志記錄,有一個特別的日志管理器我將會在
另一篇文章里講述日志記錄是如何寫入到日志文件的)
首先讓我們來看一下一些Buffer Pool 的一些相關概念。一個簡單的Buffer Pool 概念圖就像下圖那樣
POOLS AND CACHE STORES
緩沖池通常會緩存同類的、無狀態的數據。所有類型的數據在緩存池中會被視為平等的
例如:連接池或者網絡緩沖區
緩沖池的最大作用:拉近了磁盤和CPU的距離,因為數據存放在磁盤,如果經常讀取磁盤里的數據會使CPU一直等待,而這個時候緩沖池就將這種距離
拉近了,將磁盤的數據緩存在緩沖池,使性能有極大的提升
Cache stores 通常被用作緩存狀態數據和提供一組內存分配接口給不同的客戶重用。
例如存儲過程緩存會分為幾個不同的cache stores
1、第一種用來存儲ad-hoc類型SQL 執行計劃
2、第二種用來存儲存儲過程、函數、觸發器等的執行計劃
3、第三種用來存儲擴展存儲過程的執行計劃
The Free List
SQLSERVER會維護著一個最小數量的空閑頁面記錄在空閑列表里以能夠最快處理傳入的請求。
SQLSERVER會盡量在空閑列表里維護著空閑頁面的數量(“Min Free“ 在 DBCC MEMORYSTATUS 的輸出里面)
的計算是根據 Buffer Pool的大小和傳入的請求數(頁面平均壽命,在緩存里面頁面的壽命就是一個指標)
大家在運行 DBCC MEMORYSTATUS 的時候有沒有留意他的輸出結果,實際上每一個節就是一個cache store
理解:
cache:緩存
store:店鋪
在SQLSERVER Buffer Pool里有很多這樣的緩存店鋪(cache store),而每家店鋪賣的東西是不一樣的,更有趣的是每家店鋪里
只賣同一樣商品
對緩存頁面進行寫操作和釋放操作
SQLSERVER使用LRU-K(Least Recently Used 近期最少使用算法 改進了的LRU算法)去計算在Buffer Pool里的頁面壽命
MYSQL和ORACLE也是使用的LRU算法來清除緩存,也對LRU算法進行了改進
基本上,當一個頁面每引用一次,計數器就會上升,當lazy writer 進程將頁面請出緩存的時候,計數器也會降下來
其他工作線程在特定時刻(例如當一個異步I/O發生的時候)會檢查當前Buffer Pool的內存狀態確保對新的請求有足夠
數量的空閑頁面可用。如果空閑的緩存不夠,那么會有兩件事情發生:
事件一:如果 Buffer Pool的上限已經達到了(這個上限是根據 “max server memory”和當前操作系統的可用內存來的)
這兩個都會反映在SQL Server Memory Manager:Target Server Memory 這個計數器)
lazywriter 進程會清除部分 Buffer Pool 緩存
lazywriter 進程清除Buffer Pool 緩存的幾種策略:
1、他會跟蹤自上次清除緩存時沒有被清除的頁面,這一次進行清除
2、根據頁面最后一次被引用的時間,如果太久沒有引用則清除
3、數據頁面是否是臟頁,如果是臟頁面則刷入到磁盤中(dirty page才需要刷入磁盤,修改磁盤上的頁面數據,而clean page是不需要刷入磁盤的,因為他在內存里無做任何修改)
清除完畢之后會修改Free List,告訴Free List當前有哪些空閑的頁面,如果事務日志記錄還沒有寫入到磁盤,那么臟頁是不會被刷入的直到事務日志記錄
已經寫入磁盤
事件二:如果 Buffer Pool還沒有達到上限
那么SQLSERVER提交更多的預留頁面( reserved pages 向操作系統申請更多的內存)到Buffer Pool里,而不是像剛才那樣,
清除一些頁面讓這些清除后的頁面重新回歸到Free List
這就是為什麼Page Life Expectancy 這個計數器在一臺瓶頸很小的服務器里會非常高的原因(因為系統還有很多內存)
數據頁面不需要被請出 Buffer Pool。
而且Process:Private Bytes (sqlservr.exe) 和SQL Server Memory Manager: Total Server Memory 會一直增長,即使在一臺服務器上
活動比較少
刷寫數據頁面和釋放數據頁面的三個線程
(一)Lazywriter 線程
Lazywriter 線程是一個系統線程,他會將一批在buffer pool里的臟頁刷出并修改buffer pool的Free List
釋放buffer pool里的部分頁面,將這部分釋放的頁面的內存返還給操作系統
Lazywriter 線程的主要工作是維護空閑列表 free list
(二)Checkpoint 線程
Checkpoint 線程也是一個系統線程,他會在一定時間里喚醒并檢查每個數據庫是否超過了Recovery interval
他的主要工作是把臟數據頁面刷到磁盤,以便在數據庫還原的時候減少事務日志undo和redo的事務數,
然而,Checkpoint 不會去更新Free List
Checkpoint 只是把buffer pool中的臟頁面修改到磁盤上的頁面上,做完Checkpoint 之后,buffer pool里面的頁面還是存在的,沒有釋放的
(二)Eager Write 線程
Eager Write 線程是一個特別的寫機制用作 non-logged 的I/O操作的線程,例如BULK INSERT和SELECT INTO.
這個線程的目的是清除一種叫做Buffer Pool 的無用頁面(當發生大容量的數據操作,例如BULK INSERT的時候,
讀入到Buffer Pool里的這些數據頁面一般不太可能重用),所以當完成大容量操作之后會由Eager Write 線程將這些數據頁面進行清除
Eager Write 線程和Lazy writer 線程的區別:
Lazy writer 線程:當操作系統中可用內存不足或者buffer pool已經達到上限 ,而有新請求需要使用數據頁面的時候,Lazy writer 線程才會觸發,所以叫Lazy
而Lazy writer在清除數據頁面的時候,會等事務日志記錄flush到磁盤之后才會將數據頁面flush到磁盤
在 NUMA系統里面,每一個NUMA節點都會有一個 Lazy Writer線程
Eager Write 線程:做完大容量操作之后,會馬上進行數據頁面清除工作,所以叫Eager(勤奮)
公式
總結
文章簡單介紹了Cache Store的來歷和SQLSERVER Buffer Pool的結構,希望對大家理解SQLSERVER Buffer Pool有幫助
如有不對的地方,歡迎大家拍磚o(∩_∩)o
2014-6-8補充
從SQLSERVER2005開始,使用最新的LRU-K算法清除緩存中的頁面
文章列表