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语句引发的,就如我前面提到糟糕的查询(缺失索引、排序、哈希等等),这个时候经过语句优化能够很好的解决突发问题,这里就不详解了。若是服务器广泛存在文章中出现的内存性能计数器问题,那就写报告提交内存增长需求吧。

相关文章
相关标签/搜索