以下概念按sqlserver 2005及2008中描述,2012中有改变,参考系列最后一篇。
与其他数据库相比,sqlserver可调整的内存参数很少,只有以下几个:
定义sqlserver最小buffer pool值。
注意以下两点:
定义sqlserver最大buffer pool值。
也注意以下两点:
一般而言,SqlServer发生内存泄漏可能性很小。如果是刚启动的SqlServer,占用内存会逐步增大至max server memory (MB)参数设置的最大值(修改不需重启)而后渐趋平稳。如果未设置该参数,Windows默认是2048TB,相当于无限制;Linux默认是操作系统内存的80%,留20%是为避免被OOM。
启用AWE以突破32位服务器2G用户寻址,sqlserver 2012开始已不支持。
企业版自动开启,可以在一定程度上确保sqlserver物理内存数,当然如果windows内存压力太大,开启也救不了。
1)database cache:缓冲池,类似oracle buffer cache,通常是最大的区域
2)各类consumer:sqlserver功能组件统称为consumer,主要包含:
3)线程内存:sqlserver为进程内的每个线程分配0.5M内存,存放线程数据结构及相关信息
4)第三方代码:由于它们不是sqlserver自身代码,所以sqlserver也不知道它们申请了多少内存。一般这块内存不会很大,除非第三方代码存在大量内存申请甚至内存泄漏,或者linked server需要从远端数据库取大量数据。
1)先reserve再commit:database cache使用的申请方式
2)直接commit(称为stolen):database cache之外其他部分内存使用的申请方式
之所以区分这两种申请方式,是因为sqlserver不会对stolen的内存使用AWE功能。也就是说,32位服务器AWE扩展的内存只能存放database cache数据,其他内存还是要在2G里想办法。
1)single page allocation:对所有可以分成<=8KB为单位的内存申请,sqlserver分配一个页面(8KB)。这些页面集中在一个内存区域管理,这个内存区域称为buffer pool。
2)multiple page allocation:对>8KB为单位的申请,sqlserver将它们存在另一个区域,这个内存区域称为multi-page(以前叫MemToLeave)。
下面按用途分,看看各种类型使用多大内存,存放在什么区域。
1)database cache:都是数据页面,均以8KB为单位,放在buffer pool。
2)各类consumer:
3)线程内存:每个线程分配0.5M内存,自然放在multi-page
4)第三方代码:由于不是sqlserver自身代码,sqlserver也不知道它们申请了多少内存,所以都放在multi-page
当然不一定,因为windows内存多不代表sqlserver就能用到:
也不一定。前面提到过,sqlserver在启动时只申请需要的内存,随着用户使用,sqlserver会继续申请内存直到windows有压力或者到达Max Server Memory参数上限,这种持续上涨是正常的。
作为一个成熟的软件,sqlserver本身发生内存泄漏的可能性很低,应用程序发生内存泄漏的可能性更高一点。
这个也在前面提到过,Max Server Memory只能控制sqlserver buffer pool部分内存最大值,这不是sqlserver内存的全部,所以内存使用量大于这个值很正常(但不应大太多)。
如果这类问题发生,对SqlServer影响会非常大。轻则SqlServer响应异常缓慢,重则大量用户无法连接SqlServer,SqlServer短暂hang死。错误日志中常常能看到如下告警:
spid1s a singnificant part of sqlserver process memory has been paged out.
this may result in a performance degradation(性能降级)
duration:0 seconds
working set:1086400 commited:2160928 memory utilization:50%
如果能确定是multi-page内存不足导致的问题,适当增加multi-page当然可以提高sqlserver性能
如果不是,加大了未必会有用。尤其在32位未开启AWE的服务器,sqlserver可用内存只有2G,加大multi-page就意味着要减小buffer pool,很有可能得不偿失。
其实从windows层面,任何内存都需要先reserve再commit。
为什么stolen部分可以直接commit?是因为在sqlserver中,buffer pool已经将所有将需要的内存提前reserve了。
如果sql要做的是用buffer pool已经reserve的地址空间去commit,而commit后的内存又不存放database cache数据,这部分内存就被称为stolen。