资源调控器故障排除

本主题提供了针对在使用资源调控器时可能发生的一些情况的故障排除指南。本指南可归纳为以下类别:

  • 错误

  • 意外结果

  • 与性能有关的问题和错误

资源调控器错误

资源调控器错误消息涉及与配置和使用资源调控器有关的所有操作。

下表提供了资源调控器错误消息的示例,并就如何解决相应错误消息中描述的问题提供了指导。

错误号

错误消息

解决方法

8645

等待资源池 'myTestPool' (257)中的内存资源来执行该查询时发生超时。请重新运行该查询。

将超时值配置为较大的值,或者减少服务器的查询负载。

8651

因为请求的内存授予在资源池 'myTestPool' (257)中不可用,所以无法执行此操作。请重新运行该查询,降低查询负载或检查资源调控器配置设置。

以后再运行该查询。减少服务器上的查询负载。请管理员检查资源调控器配置设置。

8657

因为 1024 KB 超出了工作负荷组 'myTestGroup' (267) 和资源池 'myTestPool' (257) 的最大配置限制,无法获得该内存授予。请与服务器管理员联系以增大内存使用量限制。

请重写查询以减少占用内存的操作,如排序和哈希联接。请系统管理员设置更高的内存使用量限制。

管理员可以调整以下两个参数中的一个,也可以对这两个参数都进行调整:

  • 资源池的 max_memory_percent,此参数用于设置授予所有查询的最大物理内存空间。

  • 工作负荷组的 request_max_memory_grant_percent,此参数用于设置针对每个查询的限制。

管理员可以从 sys.dm_exec_query_resource_semaphores 中的 max_target_memory_kb 列获得实际的物理限制。

针对每个查询的限制可以通过 max_target_memory_kb * request_max_memory_grant_percent 计算得出。

注意注意
管理员需要确保此错误消息中指出的所需内存少于通过上面的计算得到的针对每个查询的限制。但应注意,增大 request_max_memory_grant_percent 值会产生副作用,即减少可以并发运行的大型查询数目。例如,采用默认 25% 的设置时,用户可以运行三个大型查询,但采用 40% 的设置时,只能运行两个大型查询。

10900

启动期间未能配置资源调控器。请查看 SQL Server 错误日志,了解具体的错误消息,或运行 DBCC CHECKCATALOG('master') 检查 master 数据库的一致性。

尝试运行“DBCC CHECKCATALOG('master')”。

10901

用户没有更改资源调控器配置的权限。

请授予允许修改资源调控器配置的权限,然后重试。

10902

master 数据库中不存在用户定义函数 'dbo.rgclassifier_v1',或者该用户没有访问该函数的权限。

master 中创建分类器用户定义函数 (UDF),或授予对现有分类器 UDF 的所需权限。

10903

为分类器用户定义函数指定的架构名称 'dbo' 不存在,或者该用户没有使用该名称的权限。

尝试使用其他架构名称或者获得对此架构的正确权限。

10904

资源调控器配置失败。在要删除或移动到其他资源池的工作负荷组中存在活动会话。请断开受影响的工作负荷组中的所有活动会话的连接,然后重试。

断开受影响组中的所有活动会话的连接,然后重试。

注意注意
此版本的资源调控器不允许在池与池之间移动含有打开的会话的组。

10905

内存不足,无法完成资源调控器配置。请降低服务器负载或在专用管理员连接上尝试该操作。

降低服务器上的负载或使用专用管理员连接尝试配置操作。

10906

对象 'dbo'.'rgclassifier_v1' 不是有效的资源调控器分类器用户定义函数。有效的分类器用户定义函数必须绑定到架构、返回 sysname 且没有参数。

提供有效的分类器 UDF。有效的分类器 UDF 必须满足以下条件:

  • 返回 sysname。

  • 没有参数。

  • 是使用 SCHEMABINDING 选项创建的。

10907

值为 50 的属性 'MIN_CPU_PERCENT' 大于值为 40 的属性 'MAX_CPU_PERCENT'。

提供小于或等于最大值的最小值。

10908

值为 40 的属性 'MAX_MEMORY_PERCENT' 小于值为 60 的属性 'MIN_MEMORY_PERCENT'。

提供大于或等于最小属性值的最大值。

10909

无法创建资源池。资源池的最大数目不能超过当前限制 20 (包括预定义的资源池)。

删除不需要的资源池。

10910

操作无法完成。指定的 'MIN_CPU_PERCENT' 值 25 导致所有资源池上最小值的和超过 100%。减小该值或修改其他资源池,以便使该和小于 100。

减小 MIN_CPU_PERCENT 的值。

10911

资源池 'myTestPool2' 不存在,无法执行请求的操作。

查询 sys.resource_governor_resource_pools 目录视图以查看当前定义了哪些资源池。选择现有池或创建新池。

10912

操作无法完成。不允许删除预定义的工作负荷组。

选择用户创建的工作负荷组进行删除。

10913

用户不可以对 'internal' 资源池中的工作负荷组 'internal' 进行删除。

在用户创建的池或默认池中创建工作负荷组。

10914

工作负荷组 '#mygroup' 的名称不能以 ## 的 # 开头。

在创建组或池时请勿使用 # 和 ##。

10915

操作无法完成。不允许更改 'internal' 工作负荷组。

选择用户创建的池或组进行更改。

注意   允许更改默认组或资源池的配置。

10916

由于资源池 'myTestPool' 包含工作负荷组 'myTestGroup',因此无法删除该资源池。请先删除使用此资源池的所有工作负荷组,再删除资源池。

删除或移出使用此池的所有工作负荷组,然后再删除此池。

10917

ALTER WORKLOAD GROUP 失败。必须指定 'WITH' 或 'USING' 子句。

在 ALTER WORKLOAD GROUP 语句中使用 'WITH' 或 'USING' 子句。

10918

无法创建资源池 'myTestPool',因为它已存在。

选择其他资源池名称。

10919

从 master 数据库中读取资源调控器配置时出错。请检查 master 数据库的完整性或与系统管理员联系。

尝试运行“DBCC CHECKCATALOG('master')”。

10920

无法删除用户定义的函数 'dbo.myclassifer'。它正被用作资源调控器分类器。

无。

10921

无法将 'default' 工作负荷组移出 'default' 资源池。

不适用。

10981

资源调控器重新配置成功。

此消息写入到 SQL Server 事件日志中。

10982

无法运行资源调控器分类器用户定义函数。请参阅 ID 为 58 的会话的 SQL Server 错误日志中以前的错误,以了解详细信息。分类器所用时间: 800 毫秒。

此消息写入到 SQL Server 错误日志中。

注意   SQL Server 错误日志中具有相同服务器进程标识符 (SPID) 的以前的消息可能会提供具体的失败原因。分类器长时间运行可能会造成用户登录超时。请检查分类器所用时间是否超过了客户端登录超时值。

10983

用户取消了资源调控器重新配置。

不适用。

10984

资源调控器重新配置失败。

不适用。

意外结果

意外结果说明了这样的情况:资源调控器的各种元素都正常运行,但产生的结果不是您预期的结果。例如,会话分类似乎不正确,或者存在与删除或创建工作负荷组有关的问题。

会话分类

当出现以下情况时,会话将分类到默认工作负荷组:

  • 分类器 UDF 不存在或未启用。

  • 分类器 UDF 对会话置之不理,这表明在函数逻辑方面存在缺陷。

基本故障排除

如果没有可用来进行分类的分类器 UDF,则所有会话都将自动分类到默认工作负荷组。创建分类器 UDF 后,您需要验证是否向资源调控器注册了它以及是否更新了内存中的配置。

创建、注册和启用分类器 UDF 的过程包括三步:

  • 首先,需要创建此函数。

    CREATE FUNCTION function_name() RETURNS <something> 
    WITH SCHEMABINDING
    
  • 其次,需要向资源调控器注册此函数。

    ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION=schema_name.function_name)
    
  • 再次,需要更新资源调控器在内存中的配置。

    ALTER RESOURCE GOVERNOR RECONFIGURE
    

排除分类方面的故障时首先应做的事情就是验证是否向资源调控器注册了您创建的函数以及是否更新了相应配置。使用下面的查询可获得资源调控器当前正在使用的分类器 UDF 的架构名称 (schema_name) 和分类器函数名称 (function_name)。

USE master
SELECT 
      object_schema_name(classifier_function_id) AS [schema_name],
      object_name(classifier_function_id) AS [function_name]
FROM sys.dm_resource_governor_configuration

您更改了分类器 UDF,但资源调控器仍在使用以前的函数逻辑来对会话进行分类,在这种情况下您可以使用前述方法进行故障排除。此行为表示您所做的更改未应用于内存中的配置。

高级故障排除

您可能会创建不产生预期结果或占用大量资源的非常复杂的分类器函数。如果您已经进行了基本故障排除,那么您就需要验证函数逻辑是否合理。最糟糕的情形是,因存在代码编写方面的缺陷而造成无限循环或失控查询。

可以使用专用管理员连接 (DAC) 来排除编写拙劣的分类器函数的故障,因为 DAC 不进行分类,可以在资源调控器运行并对传入会话进行分类时使用。有关详细信息,请参阅使用专用管理员连接

注意注意

如果没有 DAC 可用来进行故障排除,则可以在单用户模式下重新启动系统。虽然单用户模式不进行分类,但您无法在资源调控器分类运行时对它进行诊断。

可通过查询以下内容获得有关分类器函数的信息:

  • sys.dm_exec_query_stats(包含语句信息,但不包含实际函数)

  • sys.dm_exec_sql_text(与从 sys.dm_exec_query_stats 获得的 sql_handle 一起使用)

  • PreConnect:Starting 事件类(提供分类器函数的 ID 和名称)

重新配置失败

在 ALTER RESOURCE GOVERNOR RECONFIGURE 语句执行完之前,资源调控器会使元数据更改独立于正在运行的会话。如果尝试删除包含活动会话或打开的会话的组,或者尝试删除包含工作负荷组的资源池,则 ALTER RESOURCE GOVERNOR RECONFIGURE 将失败。

若要获得内存中的配置和存储的配置,请分别查询 sys.dm_resource_governor_configuration 和 sys.resource_governor_configuration。is_reconfiguration_pending (sys.dm_resource_governor_configuration) 的值为 1 时表示会话配置尚未更新。如果出现这种情况,那么可供您选择的方案如下:

  • 等待会话完成或删除其连接。

  • 显式停止活动会话或删除会话连接。

  • 重新创建您已删除的组或池,调整其设置,然后重新运行 ALTER RESOURCE GOVERNOR RECONFIGURE。

与性能有关的问题和错误

如果在您使用资源调控器时似乎存在性能问题,则您需要确定此问题是否是由资源调控器配置造成的。本部分中提供的故障排除指导分为以下两个类别:

  • 会话分类

  • 查询执行

会话分类

登录触发器或分类器用户定义函数 (UDF) 长时间运行可能会影响服务器性能。如果登录触发器或分类器 UDF 的完成时间很长,则连接将会超时。但此触发器或函数会继续运行并占用服务器资源。

如果怀疑存在以预连接状态运行的会话,请使用专用管理员连接登录,然后检查 PreConnect:Starting 事件类以查看是否存在多个已启动但尚未完成的请求或会话。

若要解决此问题并防止其再次发生:

  • 停止这些会话

  • 确定造成函数或登录触发器长时间运行的可能的原因

  • 删除或替换造成此问题的触发器或函数

查询执行

查询在经过分类后执行时,它可能看起来停止响应(挂起)或失败。您怀疑当前资源调控器设置可能是造成这种情况的原因。您需要调查资源调控器配置的以下方面:

  • 请求计数限制

  • 最大 CPU 限制

  • CPU 带宽限制

  • 内存授予大小

  • 内存授予超时错误

  • 内存不足错误

  • 非最优查询计划

请求计数限制

在这种情况下,用户报告性能出现下降,您怀疑请求计数受到限制。

您首先需要验证是否显式为此用户所属的组配置了请求计数限制,方法是:检查此用户的组成员资格,以查看是否启用了 GROUP_MAX_REQUESTS 设置。如果未启用 GROUP_MAX_REQUESTS,则不存在显式请求计数限制。您应通过采取以下步骤做进一步调查。

  • 查询 sys.dm_os_waiting_tasks,以查看 RESMGR_THROTTLED 等待类型中是否有任何正在等待的请求。存在这种等待类型表明存在请求计数限制。

  • 启动性能监视器,然后使用 Queued requestsActive requests 计数器收集数据。如果 Queued request 计数不为零,则表明存在请求限制。

  • 检查 Active requests 值是否与 GROUP_MAX_REQUESTS 设置匹配。如果 Active requests 值高于 GROUP_MAX_REQUESTS 设置,则组可能会有无法限制的请求(如打开的事务)。

  • 如果 Queued requests 为零,请检查共享同一资源池的所有工作负荷组的 Active requests,因为该池可能已因为请求数过多而超载。

最大 CPU 限制

如果您有受资源调控器事件生成驱动的策略,则在达到最大 CPU 限制时您可以使用生成的事件。

在这种情况下,您需要确定您为检测占用过多 CPU 资源的查询而配置的最大 CPU 限制 (REQUEST_MAX_CPU_TIME_SEC) 是否过低。

以下操作将有助于您验证 CPU 限制设置。

  • 启动 SQL 跟踪会话,然后收集 CPU Threshold Exceeded 事件。当用户请求达到最大 CPU 使用限制时,服务器会自动生成一个 SQL 跟踪事件。如果您的设置过低,将会生成大量这种事件。
注意注意

该事件还会显示为一个服务器事件通知,所以您可以编写对该事件做出响应的脚本。

  • 启动性能监视器,然后使用 Max request cpu time (ms) 计数器收集数据。您可以参照此计数器的值来为工作负荷组设置适当的限制。

CPU 带宽限制

在这种情况下,您怀疑 CPU 带宽受到限制,原因是 CPU usage % 性能计数器达到或接近资源调控器的 MAX_CPU_PERCENT 设置值。下面的查询返回一个 SQL Server 实例的所有工作负荷组和资源池的 CPU 使用百分比值。

select * from sys.dm_os_performance_counters where counter_name = 'cpu usage %'

有关详细信息,请参阅 sys.dm_os_performance_counters (Transact-SQL)

您可以通过对系统执行以下检查来确定 CPU 带宽是否受到限制。

  • 检查服务器 CPU 的总使用率。如果有 SQL Server 以外的负载当前处于活动状态,它可能会影响您正在进行故障排除的查询。

  • 检查各个资源池的 CPU 使用率分布。资源池可能会因为其他池的 CPU 最低使用率配置值较高而受到限制。将计数器的预期值(计算得出的 CPU 使用率)与实际 CPU 使用率进行比较。

  • 检查分配给相关资源池的工作负荷组。其他工作负荷组带来的负载可能会影响共享同一池的用户。

  • 检查各个计划程序的 CPU 使用率分布。您所调查的查询可能针对的是包含长时间运行的查询的计划程序。在这种情况下,此查询可能看起来受到限制,但实际问题在于各个计划程序之间负载分布不均。

  • 检查是否可能存在这样的情况:工作负荷受到其他会话的阻碍,而不是受到资源调控器设置的限制。

  • 检查系统中当前正在运行查询的会话数目。随着并发执行的请求数目的增长,SQL Server 将试图确保所有这些请求都至少收到一定量的 CPU 时间以防出现 CPU 匮乏。

内存授予大小

在这种情况下,您怀疑所授予内存的大小是导致查询运行缓慢的原因。

资源调控器通过减少所授予的内存量来强制实施最大查询内存限制,以便大型查询不超出此限制。如果查询获得的内存授予不足 100%,可能有必要溢出临时数据并将其写入磁盘,这样做对性能的提升有明显的效果。

您需要确定大型查询所占的百分比,以便设置适当的最大查询大小限制。以下操作将有助于确定最佳设置:

  • 查询 sys.dm_exec_query_memory_grants 以查看当前内存授予状态。ideal_memory_kb 列显示了根据基数估计确定的理想量。requested_memory_kb 列显示了请求的量,在达到最大查询限制后,此量可能会降低。如果 requested_memory_kb 大大低于 ideal_memory_kb,则查询最终可能会频繁溢出(假定基数估计正确)。

  • 启动性能监视器,然后使用 Reduced memory grants/sec 计数器收集数据。此计数器的值表示在达到最大请求大小限制后收到的量低于理想量的内存授予计数的比率。大型查询在运行速度方面可能会远远慢于具有理想量的那些查询,因为它们需要溢出到磁盘才能不超出内存限制。

若要缓解内存授予问题,您可能需要增加池大小限制值或最大内存大小限制值。

注意注意

如果您只增加最大内存大小,可能会导致可并发运行的大型查询数减少。

内存授予超时错误

在这种情况下,查询因出现内存授予超时错误而失败。

但在工作负荷组和资源池定义中指定的活动内存授予请求总数和内存限制可能会在内存授予超时方面起到一定的作用。如果单个资源池由多个资源组共享,则其他组中的并发查询数目也可能影响内存授予超时。

以下操作将有助于确定最佳资源池设置:

  • 查询 sys.dm_exec_query_memory_grants 以查看此组及池的内存授予数和正在等待的查询数。

  • 查询 sys.dm_exec_query_resource_semaphores 以查看总的内存授予量和目标数。

如果授予使用的内存量大于可用内存空间,则您可以考虑增加资源池大小限制值。

内存不足错误

查询因出现内存不足错误而失败。

基本故障排除

以下操作将有助于确定最佳工作负荷组设置:

  • 查询 sys.dm_os_memory_brokers 以检查资源池内的相对内存分布和趋势。如果请求数过多而内存空间过少,则可能导致工作负荷组/资源池过载,并造成内存不足错误。

  • 启动性能监视器,然后使用与内存有关的资源工具计数器收集数据,以获得所授予内存、缓存内存和编译/优化器内存的目标及当前内存使用率。如果当前值大于目标值,则意味着资源池过载。此时可以考虑更改池的内存限制。

  • 启动性能监视器,然后使用 request max memory grant 计数器收集数据。如果此计数器值超过工作负荷组中的 REQUEST_MAX_MEMORY_GRANT_PERCENT 设置所确定的值,则查询将有可能失败。此时可以考虑更改工作负荷组限制。

高级故障排除

内存不足 (701) 错误属于一般性错误,在以下情况下返回:任务尝试从内存管理器中分配内存块,但这种尝试失败。有关详细信息,请参阅 MSSQLSERVER_701

以下情况可能会引发此错误:

  • 内存池达到其总量限制。
注意注意

这种情况可能并非完全由资源调控器造成的。服务器上可能有其他一些正在运行的应用程序,它们的内存需要促成了这种情况。

  • 多页或虚拟地址空间分配失败,原因是虚拟地址空间没有足够大的可用块来容纳所需保留项。这很有可能发生在 32 位体系结构上,不太可能发生在 64 位体系结构上。

  • 多页或虚拟地址空间分配失败,原因是总提交量达到提交限制。32 位和 64 位体系结构上都有可能发生此问题。

当您看到内存不足错误时,最好从错误日志着手调查此错误。日志包含与下例类似的输出:

2006-01-28 04:27:15.43 spid51 Failed allocate pages: FAIL_PAGE_ALLOCATION 1

错误日志中可能记录的失败有:

  • FAIL_PAGE_ALLOCATION,后面跟着尝试分配的页数

  • FAIL_VIRTUAL_RESERVE,后面跟着尝试保留的字节数

  • FAIL_VIRTUAL_COMMIT,后面跟着尝试提交的字节数

请务必了解,触发内存不足错误的任务往往不是引发此错误的任务。除非有失控任务,否则内存不足情况通常是多个正在运行的任务共同促成的最终结果。因此,在遇到十分常见的 FAIL_PAGE_ALLOCATION 错误时,必须调查更大范围的系统活动。

错误日志中另一项有用的信息是内存状态输出。根据失败的不同,您应该查找各个内存 Clerk 的单页数值、多页数值、保留的虚拟内存数值或已提交的数值。识别最大的内存占用者是继续调查此错误的一个关键步骤。通常,最大的内存占用者属于以下类型:

  • MEMORYCLERK_* 表示服务器配置或工作负荷需要分配特定量的内存。SQL Server 组件有对应的内存 Clerk,并且单个组件可以有多个内存 Clerk。有关详细信息,请参阅 sys.dm_os_memory_clerks。有时您可以根据内存 Clerk 识别造成问题的工作负荷,但您更有可能需要通过检查与 Clerk 关联的内存对象来找出占用大量内存的原因。

  • CACHESTORE_*、USERSTORE_*、OBJECTSTORE_* 是缓存的类型。缓存占用较多内存可能意味着:

    • 内存已从缓存中分配出来,但尚未作为可以逐出的项插入。这与上面的 MEMORYCLERK 情况非常相似。

    • 所有的缓存项都正在使用,所以无法将它们逐出。可通过查看 sys.dm_os_memory_cache_counters 并比较 entries_count 列和 entries_in_use_count 列的值来确认这一点。

  • MEMORYCLERK_SQLQERESERVATIONS 显示了查询执行 (QE) 保留用于运行带排序/联接的查询的内存量。在保留的量很高时发生的内存不足错误通常表示服务器中存在 Bug。

错误日志中的内存状态输出还将显示已用尽的内存池。每个池的内存中介器显示了盗用的(编译)内存、缓存的内存和保留的(授予的)内存之间的内存分布。三个中介器的编号对应于前面与内存 Clerk 关联的内存对象。您可以根据给定的 Clerk 或内存对象查出为一个池分配的内存量,方法是使用自定义脚本从完整转储提取信息;此外,sys.dm_os_memory_cache_entries 动态管理视图显示了与每一项关联的 pool_id。

如果需要与客户支持服务部门联系,请为我们的支持人员收集以下信息:

  • 显示内存不足错误以及出现此错误时的内存状态输出的错误日志。

  • 执行以下语句所得到的输出:

    dbcc memorystatus
    dbcc sqlperf(spinlockstats)
    select * from sys.dm_os_memory_clerks
    select * from sys.dm_os_wait_stats order by wait_type
    select * from sys.dm_os_waiting_tasks
    select * from sys.dm_os_ring_buffers where ring_buffer_type='RING_BUFFER_OOM'
    select * from sys.dm_os_ring_buffers where ring_buffer_type='RING_BUFFER_RESOURCE_MONITOR'
    select * from sys.dm_os_ring_buffers where ring_buffer_type='RING_BUFFER_MEMORY_BROKER'
    select * from sys.dm_os_memory_cache_clock_hands
    
  • 使用 T8004 收集的内存不足转储(可选)。此小型转储将包含一些有用的信息,如环形缓冲区和自旋锁/等待统计信息。通过关闭 T8004,再重新打开它,无需重新启动服务器,即可重置 T8004 的转储计数器。

非最优查询计划

在这种情况下,您怀疑查询运行缓慢的原因是查询计划不是最优的。如果查询优化器因为资源池的内存限制设置较低而没有获得足够的内存,则它可能生成非最优查询计划。

以下操作将有助于确定最佳资源池设置:

  • Query optimizations/sec 计数器获得数据以查看工作负荷组是否有大量查询编译。

  • Suboptimal plans/sec 计数器获得数据以查看查询优化器是否频繁生成非最优计划。

如果存在上述任意一种情况,请考虑增大资源池的内存限制值。