由于创建了大量分区,SQL 处理器耗尽了内部资源

Posted

技术标签:

【中文标题】由于创建了大量分区,SQL 处理器耗尽了内部资源【英文标题】:SQL processor runs out of internal resources due to a huge number of partitions created 【发布时间】:2019-08-26 12:48:04 【问题描述】:

我的 Perl 脚本中有一个读取查询(不是存储过程),用于针对 TestID 选择最新的 TestHistoryID 值进行测试。测试(或简单的一段代码)作为回归过程的一部分运行多次。虽然 TestID 在测试中保持不变,但测试在每次运行后都会收到一个新的 TestHistoryID。通过/失败状态、完成运行时间等存储在TestHistoryIDTestHistoryID 是一个单调递增的整数)。

由于每个 TestID 有多个 TestHistoryID(DB 保留最近 50 次运行的历史记录,如果超过 50 则删除最旧的条目),我想针对每个 @987654332 获取包含最新 TestHistoryIDs 的结果集@。

我使用以下分区查询来获取最高 TestHistoryID 的行(按照 *** 上的这个问题创建查询 - How to query SQL Table and remove duplicate rows from a result set)

SELECT TestID, TestHistoryID, TestLabel
FROM 
(
    SELECT 
        TestID,
        TestHistoryID,
        TestLabel,
    row_number() over(partition by TestID order by TestHistoryID DESC) rn
    FROM TestHistoryView
    WHERE TestID IN (@test_ids)
) content where rn = 1

@test_ids 包含巨大的数字数组,例如504954、504955、504956、504957、504958、504959、504960、504961、504962 ....(40k 个数字)

此处包含重复的表列的快照,我需要删除重复项并为每个 TestID (https://i.imgur.com/7YuNIql.png) 获取 TestHistoryID 的最新值

查询最多可用于大约 10k TestIDs,如果我尝试使用 15k,则会收到以下错误:

查询处理器用尽了内部资源,无法生成查询计划。这是一个罕见的事件,仅适用于极其复杂的查询或引用大量表或分区的查询。请简化查询。如果您认为自己错误地收到了此消息,请联系客户支持服务以获取更多信息。

我需要帮助创建一个高效的查询,它不会占用传递的 40k 参数的所有资源,并且仍然返回预期的结果。提前非常感谢。

【问题讨论】:

【参考方案1】:

您实际上不能将值列表传递给单个参数。某些工具(例如 SQL Server Reporting Services)会在这种情况下重写您的查询以添加多个文字值或参数。

在任何情况下,使用 IN 列表都会将数据嵌入到查询本身中,最终会导致此问题。因此,虽然您可能认为您没有在 SQL 查询中嵌入 15,000 个单独的值,但实际上确实如此。

为避免这种情况,您需要将值与查询分开传递。您可以使用表值参数、JSON、XML 或提前加载临时表来执行此操作。使用哪个取决于您的客户端平台。我不确定您在 Perl 中有哪些选择。

对于 XML,批处理看起来像这样:

declare @ids varchar(max) = '<IDs><id>1</id><id>2</id><id>3</id><id>4</id><id>5</id><id>6</id><id>7</id><id>8</id></IDs>'

declare @doc xml = cast(@ids as xml)

SELECT TestID, TestHistoryID, TestLabel
FROM 
(
    SELECT 
        TestID,
        TestHistoryID,
        TestLabel,
    row_number() over(partition by TestID order by TestHistoryID DESC) rn
    FROM TestHistoryView
    WHERE TestID IN (select n.value('.','int') Id from @doc.nodes('/IDs/id') d(n))
) content 
where rn = 1

尽管您会省略第一行并将@ids 绑定为 varchar(max) 参数。即使将 TSQL 查询中的 XML 粘贴为文字也应该避免您当前的问题,因为将长字符串文字解析为 XML 文档不会产生与在查询中嵌入大量字符串文字相同的查询处理资源问题。

【讨论】:

David,如果我通过 XML,我必须在服务器端使用一个存储过程来处理它,这会再次产生相同的错误。你到底在暗示什么?你能在这方面举个例子吗?

以上是关于由于创建了大量分区,SQL 处理器耗尽了内部资源的主要内容,如果未能解决你的问题,请参考以下文章

linux系统inode占满故障处理

生产上数据库大量的latch free 导致的CPU资源耗尽的问题的解决

使用 matplotlib 绘制大量点并耗尽内存

静态内部类解决内存泄漏

Sqlserver In 提示查询处理器耗尽了资源

10分钟了解线程池,阿里再也不担心我线程池资源耗尽了