查询处理器耗尽了内部资源 - 超长的 sql 查询

mil*_*n m 4 sql-server sql-server-2012

我有一个 SQL Server 2012 数据库,其中包含大约 2000 个表(每日日志文件),每个表大约有 2000 万条记录。输出select @@Version

Microsoft SQL Server 2012 - Windows NT 6.2 上的 11.0.2100.60 (X64) 标准版(64 位)(内部版本 9200:)

现在,为了生成年度或 3 年报告,我需要对每个表运行查询并“联合所有”结果。查询是动态生成的,通常规模很小。但是在执行“Union all: with 1000 table”之后,它变成了一个巨大的查询。

在处理此类查询时,我收到如下突出显示的错误。

该应用程序已经构建、测试并处于实时生产中,因此我无法使用临时表或哈希表来存储中间结果。

现在,我如何摆脱此错误消息?

查询处理器耗尽了内部资源,无法生成查询计划。这是一种罕见的事件,仅适用于极其复杂的查询或引用大量表或分区的查询。

Dan*_*her 17

错误消息是有原因的。UNION在单个查询中使用数千个表是性能自杀。是的,我知道您的报告应用程序已经投入生产,但我仍然强烈建议您返回开发团队并更新应用程序,或者更好的是,改为在存储过程中重建其逻辑。

正如您在问题中建议的那样,创建一个临时表,按顺序运行每个查询并将结果转储到临时表中。然后,从临时表编译报告。所有这些都可以在存储过程中完成,存储过程还将涵盖其他重要方面,如安全性和性能。

这具有一系列优点:

  • 临时表可以被索引以提高性能
  • 您不会膨胀服务器的查询计划缓存(并且在此过程中驱逐几乎任何其他曾经缓存过的查询计划)
  • 查询不会永远“编译”(即变成执行计划)

我不是想惹你。我坚信,如果你现在不重建报告,你很可能有一天不得不继续前进。


小智 5

为了支持 Daniel Hutmacher 的完美回答,我敢打赌,如果您致电 Microsoft,他们会告诉您错误消息的内容。也许几年后,您会了解到 SQL Server 2019 支持 16,000 个表连接。

我什至不会创建临时表。我会创建一个普通的表,Megalog,填充它,并创建一个日常进程来在它被剪切时附加每天的日志。我将所有查询都基于 Megalog,并在删除关联的日志表时删除过时的行。我知道您现在受到限制,因此无法实现,但 IMO 您别无选择。您不妨拥有一张桌子来支持您的业务。

从设计的角度来看,您的错误是经典设计错误的一个很好的例子:将数据放入元数据中。元数据中的数据是 1 天日志表的存在,其数量无限制地增长。当模式无限制地增长时,它持有一些应该在行中的东西, a/k/a data

当需要修改设计时——鉴于您的问题,它似乎很快就会发生——我建议您寻找动态修改架构的情况,并寻找使用静态架构的机会。系统和您的 SQL 将变得更简单、更稳定。

肯定有人会告诉你,查询一个 2000 万行的表比查询一个 2000 亿行的表要快。在某种程度上,这是真的。但如果它是按日期聚类的,则较小的表平均仅避免 log2(2000) = ~10 次查找操作,主要针对缓存。如果您愿意做这项工作并接受复杂性,SQL Server 具有分区功能,可以使该数字过时。为此目的而编入索引的单个表的性能应该比您目前正在处理的 orangoutang 好得多。;-)