概述: 当一个SQLServer实例运行得很慢的时候,应该做一些检查,如检查 等待 状态 。最好的方法是一开始就建立一个性能基线,以便做性能对比。当发现与性能基线对比后,存在 内存 压力的话,就要找出是什么原因导致的。可以检查事务的 等待 状态 ,其中Resou
概述:
当一个SQLServer实例运行得很慢的时候,应该做一些检查,如检查 等待 状态 。最好的方法是一开始就建立一个性能基线,以便做性能对比。当发现与性能基线对比后,存在 内存 压力的话,就要找出是什么原因导致的。可以检查事务的 等待 状态 ,其中Resource_semaphore 等待 可能出现最多。下面是如何去处理这个问题:
当检查事务的所有 等待 类型后,可能会发现Resource_semaphore这个 等待 类型出现非常多,这会增加一些页面的IO 等待 。因为这些事务没有足够的 内存 来处理它们的操作,所以到这了页面的IO 等待 。
Resource_semaphore 等待 :
首先我们来弄清楚一下什么是Resource_semaphore 等待 。当SQLServer收到一个用户请求(或者查询时)。首先会创建一个编译后的计划,然后在这个基础上创建一个执行计划。当SQLServer创建一个编译后的计划时,它会计算两个 内存 授予参数,成为:请求 内存 (required memory)和额外 内存 (additional memory)
请求 内存 是运行排序和hash连接的所需最少 内存 ,之所谓成为“请求”,是因为查询不需要在一开始就申请这部分的 内存 。而额外 内存 是存放临时数据到 内存 中所需的那部分 内存 。如果没有足够的 内存 ,查询所需的数据将会存到硬盘当中。
首先,服务器会计算运行特定查询所需要的 内存 。这部分通常等于请求 内存 和额外 内存 的总和。但当实例使用并行执行时,所需的 内存 为(请求 内存 *并行度)加上额外 内存 的总和。服务器会检查是否有足够的 内存 来运行每个查询,然后会降低额外 内存 的量,知道所有总 内存 需求量刚好达到 内存 的限制量。这部分修改后的 内存 成为需求 内存 (requested memory)。在SQLServer内不能,有一个叫Resource Semaphore的设置,用于授予需求 内存 用于查询。当查询没有得到足够的 内存 ,就会把 等待 状态 改为:Resource_Semaphore。可以从sysprocesses系统表或者sys.dm_exec_request DMV中查询。
当Resource_semaphore接受一个新的请求时,首先检查是否有查询还在 等待 中,如果发现有,那么会把这个新请求放到先进先出的队列中,Resource Semaphore会尝试对未 等待 的查询授予 内存 ,这部分 内存 可能是之前的查询执行完毕后返回的 内存 。如果发现有足够的 内存 ,那么就会把 内存 赋予给处于Resource Semaphore 等待 状态 的查询,让其开始运行。如果不够,那么会把查询放入 等待 队列并标记为Resource_Semaphore 等待 。因此,看这个 等待 状态 可以发现 内存 存在压力。
识别Resource_Semaphore 等待 :
步骤1:
执行以下语句,并筛选Resource_Semaphore 等待 的数据:
[sql] view plaincopyprint?
SELECT * FROM sys.SYSPROCESSES WHERE lastwaittype = 'RESOURCE_SEMAPHORE' ORDER BY lastwaittype
由于这种情况不好模拟出来,所以没有截图。
步骤2:
从步骤1中得到的结果,可能会看到很多的事务处于ResourceSemaphore 等待 状态 ,现在可以运行下面语句来查看已分配到 内存 的查询的目前 状态 ,和未被分配 内存 的查询的数量。这个DMV会返回两行,一行是resource_semaphore_id为0的大查询,另外一些是为1的小查询,这里的小是 内存 小于5M。在这里可以获得总授予 内存 和实例上总可用 内存 。可以查看grantee_count和waiter_count,grantee_count是已经分配了 内存 的总查询数量,而waiter_count是在队列中 等待 授予 内存 的总查询数量:
[sql] view plaincopyprint?
SELECT * FROM sys.dm_exec_query_resource_semaphores
步骤3:
然后使用DMV:sys.dm_exec_query_memory_grants来获得在 等待 队列中的查询所需要 内存 的详细信息。这些查询的grant_time和granted_memory_kb可能为null。也可以从这个DMV中得到plan_handle和sql_handle:
[sql] view plaincopyprint?
SELECT * FROM sys.dm_exec_query_memory_grants
我们要关注的是下面3列:
步骤4:
现在将要找到集中 消耗 内存 的查询,可以查看所有 等待 查询中的需求 内存 。当看到这部分 内存 太大的时候,然后找到这些查询的plan_handle,并查看它们的执行计划:
[sql] view plaincopyprint?
SELECT TOP 10 * FROM sys.dm_exec_query_memory_grants
步骤5:
把步骤4中查询的plan_handle的数据复制,然后执行:
[sql] view plaincopyprint?
SELECT * FROM sys.dm_exec_sql_text(sql_handle)
注意替换括号中的sql_handle。然后查看其执行计划。
总结: 通过上面的步骤找到耗费 内存 的查询后,应该调整语句,使其占用更少的资源。以便解决 内存 压力。
查看更多关于SQLServerRESOURCE_SEMAPHORE等待状态内存消耗过多的详细内容...