原文出处:https://blogs.msdn.microsoft.com/sqlmeditation/2013/01/01/memory-meditation-the-mysterious-sql-server-memory-consumer-with-many-names/

对于多个不同名称的内存消费者

你曾经是否想知道内存授予是什么(Memory grants )?
什么是查询执行的保留(预定)内存(QE Reservations)?
以及查询执行内存(Query Execution Memory)?
工作空间内存(Workspace memory),以及内存保留(译者注:很多地方都将Reservations译作“保留”,个人认为译作“预定”一次更为容易理解,下文中预定同义与“保留”)

就好比生活中的许多事情一样,简而言之,一句话:所以的名字都指向SQL Server中的同一个内存消费者,
查询期间的为了排序或者哈希操作(包括bulk copy和索引创建等)的内存分配
请允许我引申出来更大的话题,在一个查询执行的过程中,这个查询可能会从不同的"buckets" 或者 clerks中申请内存,(从不同地方申请内的差异)依赖于申请的内存用来做什么。
例如,一个查询在最初的解析和编译时,他需要消费编译或者是优化内存。一旦查询语句编译完成之后,他所申请的内存就会释放,
同时其对应的查询执行计划会被缓存,为此,这个执行计划会消费过程缓存内存,并且这块内存一直被占用直到服务器重启或者内存发生压力,此时,查询准备好执行。
如果查询语句发生排序或者哈希操作(连接或者组合),那么它首选会使用实现预定的内存用来存储结果或者存储Hash桶(的结果)
这个部分内存发生在查询执行期间,具体会涉及到很多内存的名称。

术语和故障诊断工具

让我们回顾一下您可能会遇到的关于这个内存消耗者的不同类别。
同样,所有这些描述了与相同内存分配相关的概念:

查询执行内存 (QE Memory):
  这一项是用来强调在查询执行过程中sort/hash内存使用这个事实,同时也是查询执行期间的最大的内存消费部分。

查询内存(QE)预定或者内存预定:
  当一个查询需要sort/hash操作准备内存的时候,在执行期间,他将基于包含了sort或者hash运算的原始查询计划,执行一个内存保留请求(内存预定请求),
  然后查询开始执行,他请求内存,同时sqlserver将会授予这个查询部分或者是全部的内存请求,主要是依赖于服务器可用内存
  有一个叫做MEMORYCLERK_SQLQERESERVATIONS的内存clerk,这个内存计数器来保留这部分内存的分配的情况。

  ------------------------------译者注---------------------------------
  这部分内存可以从sys.dm_os_memory_clerks中查询出来,如下截图是一个存在负载的服务器的服务器上的MEMORYCLERK_SQLQERESERVATIONS分配情况
  可见这部分内存还是不小的,这里是有超过4GB的MEMORYCLERK_SQLQERESERVATIONS(服务器内存32GB)
  如果一个服务器没有负载的时候,这个内存的使用是很低的,甚至可以是0

  

  --------------------------------------------------------------------------

内存授予(Memory Grants):
  当SQL Server给一个请求授予请求内存的时候,称之为内存授予发生了,
  有一个性能计数器保留了已经有多少内存授予了请求内存:Memory Grants Outstanding
  另外一个计数器表明有多少查询已经请求了sort/hash内存,但是出于等待状态,因为查询执行内存已经耗尽:Memory Grants Pending
  这两个内存计数器显示了内存授予和内存授予的不足,也就是说,一个单独的查询可能消耗4GB的内存去执行一个排序,但这两种情况都不会被反映出来

  ------------------------------译者注---------------------------------
  这部分内存可以理解为实时请求内存,SQL Server实时请求越多,这部分内存就越大,
  比如一个Session需要20MB的运行内存,同时运行10个Session就需要200MB,同时运行100个Session就需要2000MB,当然每个Session需要的运行内存都不一样(memory grant),这里仅仅是举例
  可以从sys.dm_os_memory_clerks中查询出来,如下截图是一个存在负载的服务器的服务器上的MEMORYCLERK_SQLQERESERVATIONS分配情况
  可见这部分内存还是不小的,这里是有超过4GB的MEMORYCLERK_SQLQERESERVATIONS(服务器内存32GB)
  如果一个服务器没有负载的时候,这个内存的使用是很低的,甚至可以是0
  Memory Grants Outstanding某一个Session无法得到其申请的内存,处于等待内存状态,
  SQL Server是一个自我调节(self tuning)引擎,这部分内存一般会预留的足够,正常情况下不会发生因为sql的执行缺少内存而等待的情况
  凡事得分清楚轻重缓急,内存也一样分为急需的和非急需的,不能那边为了缓存数据而占据内存,而这边连实时的请求都无法响应吧。
  举个不恰当的例子,再穷,可以不买房不买车,总的留够吃饭的钱吧。
  其他地方的内存可以存在压力(比如数据缓存可能快速地被置换出内存),但是面对相应实时请求的内存,SQL Server留的还是比较充足的,个人很少见到因为Session等待内存而无法执行的情况。
  但是话不能反过来说,不能说没有出现Memory Grants Pending,就说明内存没有压力。

  

  ----------------------------------------------------------------------------

为了观察单独的请求和他们已经申请的内存,你可以查询sys.dm_exec_query_memory_grants这个DMV
这个DMV显示的是当前运行的查询的内存授予情况,而非历史情况
另外,你可以捕获实际查询执行计划,查询其一个叫做Query plan的XML节点,他包含了内存授予的大小,
如下示例:
<QueryPlan DegreeOfParallelism="8" MemoryGrant="2009216"
另外一个DMV是 sys.dm_exec_requests,包含了一个叫做granted_query_memory的8kb为单位的列,
比如一个1000的值,意味着1000*8kb,或者说是8000kb的内存授予

工作空间内存(Workspace Memory):

  这仍旧是另外一个描述同样内存的项目,
  你经常会看到这个性能技术区授予Workspace Memory (KB),反映的是当前所有用来sort/hash操作的内存使用
  最大工作空间内存(Maximum Workspace Memory (KB))数量是自SQL Server启动以来的最大的工作空间内存。
  在我看来,工作空间内存项目是一个用来描述sqlserver7.0个sqlserver2000的内存分配的一个遗留问题,在SQLServer2005以后已经作废

资源信号量(Resource Semaphore):
  为了给这个概念增加更多的复杂性,SQL Server使用一个称作信号量(semaphore)的线程同步对象来跟踪有多少已经被授予了的内存。
  想法是这样的:如果sqlserver用光了workspace memory/QE memory, 那么使用out-of-memory错误来替代查询执行失败(不是直接反馈查询失败,而是等待内存)
  它会促使查询等待可用内存,然后(得到可用内存之后)可以重新执行

  在这个过程中,Memory Grants Pending 性能计数器开始变得有意义。
  因此会在sys.dm_exec_query_memory_grants中生成wait_time_ms,granted_memory_kb = NULL, timeout_sec
  顺便说一下,这个和编译内存是在SQL Server中仅有的在内存不足的情况下,会执行等待内存的两种内存。
  在其他情况中,查询将会直接失败并报出701错误--内存不足。

在SQL Server中另外一种等待类型也昭示着一个查询是在等待内存授予--RESOURCE_SEMAPHORE
正如文档中所说的,这种情况发生,一个查询内存无法被立即授予归结于其他并发执行的查询。
频繁的等待和等待时间可能预示这个过多的并发查询,或者是过多的内存授予数量。
你可以在sys.dm_exec_requests这个DMW中观察Session级别的等待

为什么需要关注Memory Grants 或者 Workspace Memory 或者 Query Execution Memory或者不管你怎么称呼它。

过去几年对于性能问题的诊断过程中,我发现这是最常见的内存相关问题之一,应用程序经常执行一些看起来相当简单的查询,
却因为上执行大量的Sort或者hash操作而遭受到大量的性能破坏
那些查询不仅仅是在执行过程中消耗大量的内存,并且也会导致其他查询等待内存,这就是性能瓶颈。

使用上述我提供的工具(DWVs,性能计数器和实际执行计划),你可以查出来哪个查询是耗费了大量的内存,然后再考虑优化/重写的可能性

Sort/Hash操作产生的情景

提及查询重写,这里有一些可能会导致大量内存授予的情况

Sort操作产生的原因(包括但不限于以下几种情况)
  ORDER BY (T-SQL)
  GROUP BY (T-SQL)
  DISTINCT (T-SQL)
  Merge join操作是优化器选择的,其中合并联接的一个输入必须被排序

Hash Match操作产生的原因(包括但不限于以下几种情况)
  JOIN (T-SQL) – 如果SQL选择执行一个Hash操作,典型的就是缺少合理的索引导致的一个昂贵的join操作--hash join,观察执行计划
  DISTINCT (T-SQL) –Hash聚合可能会用来执行distinct操作,观察执行计划
  SUM/AVG/MAX/MIN (T-SQL)– 任何聚合操作可能会导致Hash 聚合,观察执行计划
  UNION – Hash聚合可能会用来做移除重复项

了解这些常见的原因可以帮助应用程序开发人员尽可能地消除对SQL Server的大量内存授予请求。
一如既往,基本的查询调优开始于检查查询是否有适当的索引,以帮助它们减少读取、尽可能减少或消除大型排序。

这里有个内存授予的博文供参考 http://blogs.msdn.com/b/sqlqueryprocessing/archive/2010/02/16/understanding-sql-server-memory-grant.aspx

(译)内存沉思:多个名称相关的神秘的SQL Server内存消耗者。的更多相关文章

  1. SQL Server 内存中OLTP内部机制概述(四)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  2. SQL Server 内存中OLTP内部机制概述(三)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  3. SQL Server 内存中OLTP内部机制概述(二)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  4. SQL Server 内存中OLTP内部机制概述(一)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  5. sql server 内存初探

    一. 前言 对于sql server 这个产品来说,内存这块是最重要的一个资源, 当我们新建一个会话,相同的sql语句查询第二次查询时间往往会比第一次快,特别是在sql统计或大量查询数据输出时,会有这 ...

  6. Sql Server 内存相关计数器以及内存压力诊断

    在数据库服务器中,内存是数据库对外提供服务最重要的资源之一, 不仅仅是Sql Server,包括其他数据库,比如Oracle,MySQL等,都是一类非常喜欢内存的应用. 在Sql Server服务器中 ...

  7. SQL Server 内存相关博文

    Don’t confuse error 823 and error 832 本文大意:      错误832:           A page that should have been const ...

  8. SQL SERVER 内存学习系列(二)-DMV查看内存信息

    内存管理在SQL Server中有一个三级结构.底部是内存节点,这是最低级的分配器,用于SQL Server的内存.第二个层次是由内存Clerk组成,这是用来访问内存节点和缓存存储,缓存存储则用于缓存 ...

  9. 人人都是 DBA(IV)SQL Server 内存管理

    SQL Server 的内存管理是一个庞大的主题,涉及特别多的概念和技术,例如常见的 Plan Cache.Buffer Pool.Memory Clerks 等.本文仅是管中窥豹,描述常见的内存管理 ...

随机推荐

  1. C# ModBus Tcp读写数据 与服务器进行通讯

    前言 本文将使用一个NuGet公开的组件技术来实现一个ModBus TCP的客户端,方便的对Modbus tcp的服务器进行读写,这个服务器可以是电脑端C#设计的,也可以是PLC实现的,也可以是其他任 ...

  2. CDMA码片序列问题

    要想知道到底是怎么算的 建议看见这篇博客的任何一位去先看一下这篇博客:https://blog.csdn.net/dog250/article/details/6420427 在CDMA中.每一个比特 ...

  3. Linux下初次使用github

    1.安装 1.1 使用yum安装的 命令:$ yum install git git-gui 1.2 生成密钥对,使用ssh-keygen方法 ssh-keygen -t [rsa|dsa],将会生成 ...

  4. [转]C++11常用特性的使用经验总结

    转载出处 http://www.cnblogs.com/feng-sc C++11已经出来很久了,网上也早有很多优秀的C++11新特性的总结文章,在编写本博客之前,博主在工作和学习中学到的关于C++1 ...

  5. tofile和fromfile数组内建函数

    numpy教程:基本输入输出和文件输入输出Input and output 使用数组的方法函数tofile可以方便地将数组中数据以二进制的格式写进文件.tofile输出的数据没有格式,因此用numpy ...

  6. error: invalid use of void expression

    void*类型定义的指针变量只可以接收对象的地址,而没有对象类型这个概念.所以void*指针变量是不能直接用“*指针变量”去访问,需要强制类型转换后才能“间接”访问: *(type*)指针变量,必须给 ...

  7. ios-改变图片的尺寸

    //改变图片的尺寸 -(UIImage*) OriginImage:(UIImage *)image scaleToSize:(CGSize)size { UIGraphicsBeginImageCo ...

  8. MySQL Error--The Table is full

    问题描述 在MySQL 错误日志中发下以下错误信息:[ERROR] /export/servers/mysql/bin/mysqld: The table '#sql-xxxx-xxx' is ful ...

  9. web前端常用代码于面试等资源

    https://www.cnblogs.com/moqiutao/p/4766146.html

  10. day056-58 django多表增加和查询基于对象和基于双下划线的多表查询聚合 分组查询 自定义标签过滤器 外部调用django环境 事务和锁

    一.多表的创建 from django.db import models # Create your models here. class Author(models.Model): id = mod ...