【问题标题】:"There is insufficient system memory in resource pool 'default' to run this query" during execution of stored procedure执行存储过程期间“资源池'默认'中的系统内存不足,无法运行此查询”
【发布时间】:2020-08-31 15:08:20
【问题描述】:

我正在使用循环游标的存储过程。在游标内,我正在调用本机编译的存储过程。本机编译的存储过程会插入内存优化表。

我的问题是我在一段时间(3 分钟左右)后遇到错误“资源池'默认'中的系统内存不足,无法运行此查询”。

我找到了问题,似乎插入语句(或它的底层查询)产生了问题,并增加了似乎在插入之后没有释放的内存,也没有在存储过程之后释放。

我从大约 3 GB 的已用内存(在我的数据库上)开始,当查询运行时,它逐步达到 12 GB(这是限制)并导致错误。错误发生后,内存立即下降到 3 GB,这表明它不可能是插入表大小本身的问题。在我的主存储过程中,它大约有 29 个循环(在游标中),因此游标本身可以正常工作。如果我删除插入语句(见下面的代码),一切都很好。所以问题一定是插入语句(分别是底层查询)。我不明白,为什么 SQL Server 在插入后(或至少在执行本机存储过程之后)似乎没有释放内存。

任何想法如何解决这个问题(我使用的是 SQL Server 2014)?

这里是本地编译的存储过程的代码:

create procedure [CombinedStrategies].[spInsParameterCombinationNative]
(   
    @UniqueProcessingBlockID int,
    @MS2ObjectID54RestricationParameterGroupID int,
    @MS11ObjectID54RestricationParameterGroupID int,
    @MS15SBBObjectID54RestricationParameterGroupID int,
    @MS15SBBObjectID59RestricationParameterGroupID int,
    @MS15SBBObjectID62RestricationParameterGroupID int,
    @MS15SFObjectID54RestricationParameterGroupID int,
    @MS15SFObjectID59RestricationParameterGroupID int,
    @MS15SBObjectID54RestricationParameterGroupID int,
    @MS15SBObjectID59RestricationParameterGroupID int,
    @MS15SBObjectID62RestricationParameterGroupID int,
    @MS16ObjectID54RestricationParameterGroupID int,
    @MS16ObjectID62RestricationParameterGroupID int,
    @CombinedParametersMS2 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS11 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS16ObjectID54 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS16ObjectID62 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBObjectID54 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBObjectID59 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBObjectID62 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBBObjectID54 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBBObjectID59 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SBBObjectID62 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SFObjectID54 CombinedStrategies.ParameterGroupIDs readonly,
    @CombinedParametersMS15SFObjectID59 CombinedStrategies.ParameterGroupIDs readonly
)
with native_compilation, schemabinding, execute as owner
as 
begin atomic
with (transaction isolation level=snapshot, language=N'us_english')


    -- load parameter combinations into table

    insert into CombinedStrategies.ParameterCombinationForCursorTemp
    (
        UniqueProcessingBlockID,
        MS2ObjectID54ParameterGroupID,
        MS11ObjectID54ParameterGroupID,
        MS15SBBObjectID54ParameterGroupID,
        MS15SBBObjectID59ParameterGroupID,
        MS15SBBObjectID62ParameterGroupID,
        MS15SFObjectID54ParameterGroupID,
        MS15SFObjectID59ParameterGroupID,
        MS15SBObjectID54ParameterGroupID,
        MS15SBObjectID59ParameterGroupID,
        MS15SBObjectID62ParameterGroupID,
        MS16ObjectID54ParameterGroupID,
        MS16ObjectID62ParameterGroupID
    )
    select @UniqueProcessingBlockID,
    MS2_54.ParameterGroupID,
    MS11_54.ParameterGroupID,
    MS15_SSB_54.ParameterGroupID,
    MS15_SSB_59.ParameterGroupID,
    MS15_SSB_62.ParameterGroupID,
    MS15_SF_54.ParameterGroupID,
    MS15_SF_59.ParameterGroupID,
    MS15_SB_54.ParameterGroupID,
    MS15_SB_59.ParameterGroupID,
    MS15_SB_62.ParameterGroupID,
    MS16_54.ParameterGroupID,
    MS16_62.ParameterGroupID
    from @CombinedParametersMS2 as MS2_54,
    @CombinedParametersMS11 as MS11_54,
    @CombinedParametersMS15SBBObjectID59 as MS15_SSB_54,
    @CombinedParametersMS15SBBObjectID59 as MS15_SSB_59,
    @CombinedParametersMS15SBBObjectID62 as MS15_SSB_62,
    @CombinedParametersMS15SFObjectID54 as MS15_SF_54,
    @CombinedParametersMS15SFObjectID59 as MS15_SF_59,
    @CombinedParametersMS15SBObjectID54 as MS15_SB_54,
    @CombinedParametersMS15SBObjectID59 as MS15_SB_59,
    @CombinedParametersMS15SBObjectID62 as MS15_SB_62,
    @CombinedParametersMS16ObjectID54 as MS16_54,
    @CombinedParametersMS16ObjectID62 as MS16_62
    where MS2_54.ParameterGroupID = isnull(@MS2ObjectID54RestricationParameterGroupID, MS2_54.ParameterGroupID)
    and MS11_54.ParameterGroupID = isnull(@MS11ObjectID54RestricationParameterGroupID, MS11_54.ParameterGroupID)
    and MS15_SSB_54.ParameterGroupID = isnull(@MS15SBBObjectID54RestricationParameterGroupID, MS15_SSB_54.ParameterGroupID)
    and MS15_SSB_59.ParameterGroupID = isnull(@MS15SBBObjectID59RestricationParameterGroupID, MS15_SSB_59.ParameterGroupID)
    and MS15_SSB_62.ParameterGroupID = isnull(@MS15SBBObjectID62RestricationParameterGroupID, MS15_SSB_62.ParameterGroupID)
    and MS15_SF_54.ParameterGroupID = isnull(@MS15SFObjectID54RestricationParameterGroupID, MS15_SF_54.ParameterGroupID)
    and MS15_SF_59.ParameterGroupID = isnull(@MS15SFObjectID59RestricationParameterGroupID, MS15_SF_59.ParameterGroupID)
    and MS15_SB_54.ParameterGroupID = isnull(@MS15SBObjectID54RestricationParameterGroupID, MS15_SB_54.ParameterGroupID)
    and MS15_SB_59.ParameterGroupID = isnull(@MS15SBObjectID59RestricationParameterGroupID, MS15_SB_59.ParameterGroupID)
    and MS15_SB_62.ParameterGroupID = isnull(@MS15SBObjectID62RestricationParameterGroupID, MS15_SB_62.ParameterGroupID)
    and MS16_54.ParameterGroupID = isnull(@MS16ObjectID54RestricationParameterGroupID, MS16_54.ParameterGroupID)
    and MS16_62.ParameterGroupID = isnull(@MS16ObjectID62RestricationParameterGroupID, MS16_62.ParameterGroupID)


end 

【问题讨论】:

  • 你能重写这个来消除光标吗?它们效率极低,并且可能导致非常高的资源争用。您还应该考虑使用“较新”的 ANSI-92 样式连接。它们已经有 20 多年的历史了。 sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/…
  • 我现在用一个while循环替换了光标,我做了一些进一步的分析(没有改进任何东西)。问题肯定是查询。我用一个简单的选择计数(*)替换了插入,问题仍然出现。不知何故,用于执行查询的内存在之后没有被释放。稍后我会做一些进一步的分析。
  • 用 while 循环替换光标是徒劳的。大多数情况下,结构良好的游标会胜过 while 循环。删除循环肯定会有所帮助。您在这里遇到的另一个问题是您有一种“包罗万象”的查询,由于执行计划的变化,这可能会导致一些性能问题。您可以在此处阅读有关该方面的更多信息。 sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries 你会发现最大的好处是摆脱循环。
  • 摆脱循环本身是不可能的(我猜)。我正在做的事情背后的主要思想是计算所有可能的参数组合并将它们存储在一个表中(这就是我的插入查询对参数表进行交叉连接的原因)。可能的组合将是大约 10 亿行,这将导致内存不足异常。为了避免这种情况,我将我的“组合”计算吐出到不同的“块”中,因此我使用了循环。或者您是否看到在没有循环的情况下插入 10 亿行(或更多行)的机会?

标签: sql-server tsql stored-procedures memory memory-optimized-tables


【解决方案1】:

确保对 SQL Server 可用的最大内存设置了上限,以使 OS 仍有可用内存。我通常为 OS 分配 2 GB。例如如果总可用 RAM 为 8 GB,则 SQL Server 可用的总内存上限为 6 GB。

【讨论】:

    【解决方案2】:

    问题似乎是“内存不足”问题。我缓解这个问题的方式不是作为数据库管理员,而是作为开发人员。人们需要“流式传输”或缓冲查询收集的结果,并且能够在读取更多数据和消耗更多物理内存之前放弃迄今为止已读取的内容。因此,例如读取 1GB,对这些数据行执行需要执行的操作,通过读取更多行来覆盖已经分配给对象/缓冲区/其他任何 1GB 的内存,然后再次处理这些行等等。我不想尝试在存储过程中做这样的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 2016-12-31
      相关资源
      最近更新 更多