zoukankan      html  css  js  c++  java
  • SqlServer 内存篇—— 常见内存错误与解决方法

    内存错误与内存瓶颈不同,当出现内存错误时,轻则某些特殊操作不能完成,重则整个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

  • 相关阅读:
    数据表格
    数据表格
    数据表格
    布局
    表单
    表单
    Java知识点梳理——继承
    Java知识点梳理——抽象类和接口
    面试心得与总结—BAT、网易、蘑菇街
    Java知识点梳理——多态
  • 原文地址:https://www.cnblogs.com/shujuyr/p/15073518.html
Copyright © 2011-2022 走看看