kai*_*lyn 7 sql-server memory sql-server-2012
我们使用的是 Windows 2012 R2 上的 SQL Server 2012 SP3 Enterprise Edition。
我在 sql 日志中看到了这些错误:
分配页失败:FAIL_PAGE_ALLOCATION 1
2016-06-14 04:28:27.44 spid175 错误:701,严重性:17,状态:123。
2016-06-14 04:28:27.44 spid175 资源池“默认”中的系统内存不足,无法运行此查询。
2016-06-14 04:28:27.44 服务器错误:17300,严重性:16,状态:1。(参数:)。错误以简洁模式打印,因为格式化过程中出现错误。跟踪、ETW、通知等被跳过。
2016-06-14 04:28:27.44 服务器错误:17300,严重性:16,状态:1。(参数:)。错误以简洁模式打印,因为格式化过程中出现错误。跟踪、ETW、通知等被跳过。
2016-06-14 04:28:27.44 spid131 错误:701,严重性:17,状态:123。
据我所知,它似乎在某个时候耗尽了内存。
有没有办法找出导致它内存不足的原因?
该MEMORYCLERK_SQLQERESERVATIONS
是相当高的,没有人知道那是什么呢?
MEMORYCLERK_SQLQERESERVATIONS (node 0) KB
---------------------------------------- ----------
VM Reserved 0
VM Committed 0
Locked Pages Allocated 0
SM Reserved 0
SM Committed 0
Pages Allocated 22599824
Run Code Online (Sandbox Code Playgroud)
编辑:我们在服务器上有 32 个内存,28 个分配给 SQL Server。最大内存设置为 28gb,最小服务器内存为 8gb。
这是 ErrorLog 输出的链接: ErrorLog
这是 sys.dm_os_process_memory 输出的链接: 查询输出
链接到等待类型: WaitTypes
我在内存使用量似乎更多的时候运行了它:
SELECT * FROM sys.dm_exec_query_memory_grants 其中 grant_time 为空
SELECT mg.granted_memory_kb, mg.session_id, t.text, qp.query_plan FROM sys.dm_exec_query_memory_grants AS mg CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS t CROSS APPLY sys.dm_exec_query_handle (mg.plan)选项 (MAXDOP 1) 结果:QueryMemGrants
SELECT top 50 t.text, cp.objtype ,qp.query_plan, cp.usecounts, cp.size_in_bytes >as [Bytes Used in Cache] FROM sys.dm_exec_cached_plans AS cp JOIN sys.dm_exec_query_stats AS qs ON cp.plan_handle = qs CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS t WHERE qp.query_plan.exist('declare namespace >n="http://schemas.microsoft.com/sqlserver/ 2004/07/showplan";>//n:MemoryFractions') = 1 个 cp.size_in_bytes desc 选项 (MAXDOP 1)
从 sys.dm_exec_requests 中选择 grant_query_memory,session_id,command 结果:dm_exec_requests
来自正在运行的查询之一的查询计划的 XML: QueryPlan
错误日志的输出有dbcc memorystatus
转储,我注意到的是
Process/System Counts Value(in Bytes)
---------------------------------------- ----------
Available Physical Memory 1217605632---1.1 G
Available Virtual Memory 140627167866880
Available Paging File 5656502272
Working Set 305238016
Percent of Committed Memory in WS 99
Page Faults 27923310
System physical memory high 0
System physical memory low 0
Process physical memory low 1--Memory Low
Process virtual memory low 0
2016-06-14 04:28:27.41 Server
Run Code Online (Sandbox Code Playgroud)
请注意可用的物理内存非常低。缓冲池中几乎没有内存
关于消耗更多内存的职员
MEMORYCLERK_SQLQERESERVATIONS (node 0) KB
---------------------------------------- ----------
VM Reserved 0
VM Committed 0
Locked Pages Allocated 0
SM Reserved 0
SM Committed 0
Pages Allocated 22599824 --21.5 G
Page Life Expectancy 64
Run Code Online (Sandbox Code Playgroud)
现在在最大服务器内存为 28 G 的服务器上,如果MEMORYCLERK_SQLQERESERVATIONS
占用 21.5 G 那绝对是一个问题。这就是导致 OOM 条件的原因。
什么是 MEMORYCLERK_SQLQERESERVATIONS
这是 SQL Server 中的内存管理员,它跟踪分配给查询的内存,该查询涉及执行期间的排序或散列操作。这些运算符可能是查询的最大内存使用者。
为什么会出现 OOM 错误
当执行涉及排序和散列操作的查询时,它会根据包含排序或散列运算符的原始查询计划提出保留请求。然后,当查询执行时,它会请求内存,SQL Server 将根据内存可用性部分或全部授予该请求。有一个名为“MEMORYCLERK_SQLQERESERVATIONS”的内存管理员(会计)跟踪此类请求的内存分配。现在在您的场景中可能会发生以下情况
查询请求太多的内存授予 SQL Server 只能为其提供有限的数量,这个有限的数量称为“必需内存”,因此它开始执行并在执行查询时,因为内存需求很大而 SQL Server 不能提供它,因为资源池中没有内存,查询失败并出现 OOM 错误。查询运行时所需的内存称为“附加内存”
在SQL Server 2012 Sp1 CU4中修复了错误,其中查询请求了大量内存授予,导致它非常慢或随后因 OOM 错误而失败。考虑到 QEReservations 占用了所有缓冲池的事实,不能排除错误重新出现的可能性
由于店员已经占用了 90% 的内存。新查询所需的内存不可用,查询失败并出现 OOM 错误。
您的表和索引具有倾斜的统计信息,这迫使优化器构建次优计划,导致它请求比实际需要更多的内存授予,从而产生问题。
最后,在 SQL Server 上运行的查询需要一些认真的调整。
开发人员实际上可以对排序/散列操作做些什么?
说到重写查询,这里有一些需要在查询中寻找的可能会导致大量内存授权的事情。
查询将使用 SORT 运算符的原因(并非所有包含列表):
Run Code Online (Sandbox Code Playgroud)ORDER BY (T-SQL) GROUP BY (T-SQL) DISTINCT (T-SQL) Merge Join operator selected by the optimizer and one of the inputs of the Merge join has to be sorted because a clustered index is
在该列上不可用。
查询将使用哈希匹配运算符的原因(并非所有包含列表):
Run Code Online (Sandbox Code Playgroud)JOIN (T-SQL) – if SQL ends up performing a Hash Join. Typically, lack of good indexes may lead to the most expensive of join operators
– 哈希连接。查看查询计划。
Run Code Online (Sandbox Code Playgroud)DISTINCT (T-SQL) – a Hash Aggregate could be used to perform the distinct. Look at query plan. SUM/AVG/MAX/MIN (T-SQL)– any aggregate operation could potentially be performed as a Hash Aggregate . Look at query plan. UNION – a Hash Aggregate could be used to remove the duplicates.
为了进一步了解这个问题,我需要您将以下查询的输出添加到您的问题中。我还希望您添加Paul Randal Wait stats query 的输出。查询来源为This Blog,建议您阅读该博客。
SELECT * FROM sys.dm_exec_query_memory_grants where grant_time is null
--Find who uses the most query memory grant:
SELECT mg.granted_memory_kb, mg.session_id, t.text, qp.query_plan
FROM sys.dm_exec_query_memory_grants AS mg
CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS t
CROSS APPLY sys.dm_exec_query_plan(mg.plan_handle) AS qp
ORDER BY 1 DESC OPTION (MAXDOP 1)
--Search cache for queries with memory grants:
SELECT t.text, cp.objtype,qp.query_plan
FROM sys.dm_exec_cached_plans AS cp
JOIN sys.dm_exec_query_stats AS qs ON cp.plan_handle = qs.plan_handle
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS t
WHERE qp.query_plan.exist(‘declare namespace n=”http://schemas.microsoft.com/sqlserver/2004/07/showplan“; //n:MemoryFractions’) = 1
Run Code Online (Sandbox Code Playgroud)
我希望您检查系统上运行的查询还有其他几件事。
Select granted_query_memory,session_id,command from sys.dm_exec_requests
Run Code Online (Sandbox Code Playgroud)
这将显示为系统上运行的查询授予了多少内存。
如果您可以看到 XML 实际执行计划,您MemoryGrant=xxxxx
可以为昂贵的查询收集此值。
以上所有内容将向我们展示查询是否存在问题或其他一些问题,即为什么它需要如此多的内存来执行。
编辑
从您粘贴的各种查询输出中。
您可以看到requested_memory_kb
大量查询大约为 5G,这是大内存授权,理想情况下应该是几 MB。请注意,required_memory_kb
它只有大约 5 MB 并且granted_query_memory
为 NULL,这是因为由于内存压力,SQL Server 只能提供最小内存来启动查询,但无法为查询执行提供额外的内存,导致查询失败并出现 OOM 错误。
请求巨大内存的查询的查询成本也很高,这让我相信要么统计数据有偏差,要么查询写得不好。其他可能性是适当索引不支持查询。请求如此巨大的内存授予的查询数量在数量上很好。
对于上述查询,请参阅granted_query_memory
全部以 GB 为单位。运行的前 3 个查询使用了大约 15 G 的内存,几乎使用了 50% 的内存。在 SQL Server 中,数以百万计的进程运行以某种方式需要内存,因此您可以查看 3 个查询是否使用了 50% 的可用内存,因此必然会发生 OOM 问题。
解决方案
您应该认真考虑调整上面屏幕截图中的前 4 个查询
确保你至少每周运行一次索引重建和统计更新,这样倾斜的统计数据不会迫使优化器产生错误的计划。
使用资源调控器并创建资源池和工作负载组,并运行请求在此池中授予大内存的查询。您可以使用参数限制内存请求request_max_memory_grant_percentage
。此博客中显示了一个示例。在您调整所有查询之前,这只是替代方法。
归档时间: |
|
查看次数: |
16117 次 |
最近记录: |