内存错误与内存瓶颈不同,当出现内存错误时,轻则某些特殊操作不能完成,重则整个sqlserver无响应,对sqlserver影响通常很大。
sqlserver常见的内存错误主要有以下三种:
701 —— OOM(Out of Memory)
8645 —— 语句运行时未及时申请到内存
17189 —— sqlserver无法创建新线程供新连接使用
一、 701报错
当sqlserver需要申请一段stolen内存,却发现没有地址空间可供申请,错误日志里就会有701报错。
换句话说,701报错只针对stolen部分内存,代表stolen部分内存不足了。在64位机器上,sqlserver可用内存空间得到了巨大的扩展,再遇上701错误的概率很小,这个报错基本都发生在32位机器上。
错误日志中信息如下:
Error: 701, Severity: 17, State: 123.
There is insufficient system memory in resource pool ‘internal‘ to runthis query.
在这条报错信息之前,还有一条信息指出sqlserver是在进行什么操作时遇到的701。
一般有以下两种场景:
1. multi-page地址段没有连续空间可供申请
1)原因可能有以下两种:
multi-page确实已大量被使用,剩余空间不足
multi-page被大量使用有可能是因为sqlserver自己申请了太多,这些申请可以在memory clerk中跟踪到。在随701错误一起输出的memory status报告中,应该能够找到某个clerk申请了大量multi-page。
multi-page中碎片过多
这种情况通常是第三方代码申请了大量内存。如果在errorlog里没有看到任何clerk申请了大量内存,就应该检查sqlserver是否有使用以下功能,导致第三方代码大量申请内存:
SQL CLR(尤其明显)
Linked Server
使用sp_OACreate调用COM对象
Extended Stored Procedures
2)解决方法:
参考 https://blog.csdn.net/Hehuyi_In/article/details/91050303 multi-page内存压力分析部分
2. buffer pool中stolen内存申请不到
参考 https://blog.csdn.net/Hehuyi_In/article/details/91050303 buffer pool中stolen内存压力分析
二、 8645报错
通常发生在需要申请内存进行排序或hash等操作的查询,在规定时间内没能获得足够的内存。这里申请的内存一般都是buffer pool中的。
1. 报错特征
错误日志中报错如下(最明显):
Msg 8645, Level 17, State 1, Procedure , Line 1
A time out occurred while waiting for memory resources to execute the query. Re-run the query.
sqlserver响应速度非常慢,严重影响业务
部分登录请求无法完成,用户可能遇到login failed报错
已连上的连接也可能遇到报错,错误信息不固定
不少连接正在等待resource_semaphore事件
Memory Grants Pending计数器可能不为0
2. 常见原因
sqlserver已存在严重的内存压力,哪怕很小的内存申请也难以得到满足
sqlserver本来内存压力不太大,但客户端突然发过来一些极为复杂需大量消耗内存的语句
3. 排查思路
sqlserver是否独占服务器,是否有其他应用程序大量占用了内存
检查sqlserver内存参数设置是否合理(https://blog.csdn.net/Hehuyi_In/article/details/103690404)
检查sqlserver当前运行语句及等待事件
检查sys.dm_os_memory_clerks中个clerk内存申请及变化
检查sys.dm_exec_query_resource_semaphores视图,了解每个查询资源信号量状态
select convert(varchar(30),getdate(),121) as runtime,
resource_semaphore_id,target_memory_kb,total_memory_kb,granted_memory_kb,used_memory_kb,,
grantee_count,waiter_count,timeout_error_count
from sys.dm_exec_query_resource_semaphores
检查sys.dm_exec_query_memory_grants视图,返回已经获得和仍在等待内存授予的查询的信息。
无需等待就获得内存授予的查询不会出现在此视图中,对于没有内存压力的sqlserver,这个视图应该为空。
select getdate() as runtime,
session_id,scheduler_id,DOP,request_time,grant_time,
request_memory_kb,granted_memory_kb,used_memory_kb,
timeout_sec,query_cost,resource_semaphore_id,waiter_order,is_next_candidate,wait_time_ms,
replace(replace(cast(s2.text as varchar(4000)),char(10),‘ ‘),char(13),‘ ‘) as sql_text
from sys.dm_exec_query_memory_grants
cross apply sys.dm_exec_sql_text(sql_handle) as s2
三、 17189报错
当multi-page空间不足时,sqlserver可能无法在需要时创建新线程,此时新连接无法连上,但已连上的还能正常工作。
错误日志报错如下:
Logon Error: 17189, Severity: 16, State: 1.
Logon SQL Server failed with error code 0xc0000000 to spawn a thread to process a new login or connection. Check the SQL Server error log and the Windows event logs for information about possible related problems. [CLIENT: 172.21.123.48]
可能原因如下:
当前线程数确实到达了sqlserver线程上限(不常见)
运行下面sql,检查有多少kpid<>0的spid,kpid<>0代表它当前使用线程运行,再加上sqlserver自己运行所需线程(10到20个),基本就是sqlserver当前使用的线程数
select count(*) from sys.processes where kpid<>0
multi-page内存有压力,参考 https://blog.csdn.net/Hehuyi_In/article/details/91050303 multi-page内存压力分析部分
原文链接:https://blog.csdn.net/Hehuyi_In/article/details/103908508