SQLSERVER 里 经常 看到 的CACHE STORES是神马东东? 当我们在SSMS里执行下面的SQL语句清空SQLSERVER的缓存的时候,我们会在SQL ERRORLOG里 看到 一些信息 DBCC FREEPROCCACHE 大家可以 看到 cachestore、object plans、sql plan、bound tress等名词 cachest
当我们在SSMS里执行下面的SQL语句清空SQLSERVER的缓存的时候,我们会在SQL ERRORLOG里看到一些信息
<span>DBCC</span> FREEPROCCACHE
大家可以看到cachestore、object plans、sql plan、bound tress等名词
cachestore flush <span>for</span> the <span>'</span><span>Object Plans</span><span>'</span> cachestore (part <span>of</span> <span>plan</span><span> cache) cachestore flush </span><span>for</span> the <span>'</span><span>SQL Plans</span><span>'</span> cachestore (part <span>of</span> <span>plan</span><span> cache) cachestore flush </span><span>for</span> the <span>'</span><span>Bound Trees</span><span>'</span> cachestore (part <span>of</span> <span>plan</span><span> cache) </span>
那么这些名词是什么意思呢?是什么功能组件呢?这篇文章为大家介绍SQLSERVER Buffer Pool,大家就会知道了
翻译自:Bufferpool Performance Counters
原文大意
在网上有非常多的文章、博客、帖子介绍内存配置和内存的一些情况,但是依然给大家带来了太多的误解。
这些文章都有讲到SQLSERVER 内存、虚拟内存、AWE功能还有其他的一些介绍我个人认为不能很好地对SQLSERVER内存方面的各个
性能计数器有很好的理解
在这篇文章里,我会着重讲解BufferPool的一些机制,例如你的数据页面和索引页面在SQLSERVER的内存里是怎麽存放的
在性能监视器里你能够使用这些知识去判断当前BufferPool的状态。
(当我谈论到页面的时候,我只谈论数据页面和索引页面。对于事务日志记录,有一个特别的日志管理器我将会在
另一篇文章里讲述日志记录是如何写入到日志文件的)
首先让我们来看一下一些Buffer Pool 的一些相关概念。一个简单的Buffer Pool 概念图就像下图那样
POOLS AND CACHE STORES
缓冲池会通常会缓存同类的、无状态的数据。所有类型的数据在缓存池中会被视为平等的
例如:连接池或者网络缓冲区
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(Least Recently Used 近期最少使用算法)去计算在Buffer Pool里的页面寿命
MYSQL和ORACLE也是使用的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、数据页面是否是脏页,如果是脏页面则刷入到磁盘中
清除完毕之后会修改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
Lazywriter 线程的主要工作是维护空闲列表
(二)Checkpoint 线程
Checkpoint 线程也是一个系统线程,他会在一定时间里唤醒并检查每个数据库是否超过了Recovery interval
他的主要工作是把脏数据页面刷到磁盘,以便在数据库还原的时候减少事务日志undo和redo的事务数,然而,Checkpoint 不会
去更新Free List
(二)Eager Write 线程
Eager Write 线程是一个特别的写机制用作 non-logged 的I/O操作,例如BULK INSERT和SELECT INTO.
这个线程的目的是避免一种叫做Buffer Pool 的无用物(当发生大容量的数据操作例如BULK INSERT的时候,
读入到Buffer Pool里的这些数据页面一般不太可能重用),所以当完成大容量操作之后会由Eager Write 线程将
这些数据页面进行清除
Eager Write 线程和Lazywriter 线程的区别:
Lazywriter 线程:当操作系统中可用内存不足或者buffer pool已经达到上限 ,而有新请求需要使用数据页面的时候,Lazy writer 线程才会触发,所以叫Lazy
而Lazy writer在清除数据页面的时候,会等事务日志记录flush到磁盘之后才会将数据页面flush到磁盘
在 NUMA系统里面,每一个NUMA节点都会有一个 Lazywriter线程
Eager Write 线程:做完大容量操作之后,会马上进行数据页面清除工作,所以叫Eager(勤奋)
总结
文章简单介绍了Cache Store的来历和SQLSERVER Buffer Pool的结构,希望对大家理解SQLSERVER Buffer Pool有帮助
如有不对的地方,欢迎大家拍砖o(∩_∩)o
2014-6-8补充
从SQLSERVER2005开始,使用最新的LRU-K算法清除缓存中的页面