优化一系列SQL计算 - 嵌套查询还是单独查询?

时间:2015-06-24 23:14:01

标签: sql sql-server database performance optimization

简介:

当需要有十几个嵌套计算查询时,

是否更合适
  • A)分别执行每个操作(保存到每个结果的表中,然后读取该表以进行下一个查询)
  • B)拥有大量嵌套选择

完整说明:

我正在尝试从SQL中的一系列输入表计算一些高级预测。

我正在建设十几个模块'它们被分成各自的模式,每个模块通常包括4-10个输入表和6-10个计算步骤。完成后,每个模块的所有输出都被转储到同一个输出表中。

查询范围为7k-200k行。

单个架构的/模块表可能如下所示:

  • 输入表1
  • 输入表2
  • 输入表3
  • 输入表4
  • 计算查询1结果表
  • 计算查询2结果表
  • 计算查询3结果表
  • 计算查询4结果表
  • 计算查询5结果表
  • 计算查询6结果表

  • 最终输出

每个计算查询都使用前一个(大部分)的结果。最终输出是最终计算查询的结果。计算不是很复杂:分区最大值,基本公式(+, - ,*,/)或SUM等。通常每个计算步骤只有1-3个,并且始终在同一列上。

这被分成多个计算查询(而不是一个超级公式)的主要原因是因为每个计算以不同的方式连接输出并使用不同的输入表;还因为有些是基于前一行的结果。 (例如最大分区或滞后)

我的要求如下:

  • 计算步骤1的最终输出并合并为最终输出的过程。
  • 计算最多所选计算查询并合并到其各自结果表(并停止)的过程。考虑一下这个最重要的决定'

不要需要存储中间查询的计算结果 - 只有最终输出或覆盖最终结果'如果被选中。

我的问题: 我正在尝试优化整个过程 - 此时它看起来需要大约10-15秒。我希望它是1秒 - 但我很欣赏这可能是不可能的。

我尝试了什么:

首先,我为每个计算查询创建了一个过程,将结果合并到各自的输出表中。使用此方法,每个计算查询必须从数据库中读取,然后合并到其输出中。

我尝试过临时表但是我不明白为什么这会是最佳的,因为我已经有了用于计算步骤的表格 - 这些表格在下一步中被编入索引。

然后我假设将所有查询简单地嵌套到一个超级过程中甚至可能有一系列表函数会更快。

我的问题:

然而我遇到了一个我无法找到答案的想法 - 以下是:

  • 在每个计算步骤中将结果插入表中可能会减慢进程(特别是当它们被2-4列索引时);但至少会为下一步索引数据。
  • 嵌套选​​择会节省插入数据的工作量,但这些结果不会被编入索引吗?对?还是错了?

智能索引选择结果吗?鉴于我的情况,你会对我如何处理这个提出建议。也许我错过了一些非常简单的事情。

其他信息:

  • 我的大多数较大的查询结果(150-200K)都有4列需要编制索引。
  • 我的所有表只有一列需要计算 - 其余列都已编入索引。

例如: ForecastID,组,年份,类型,子类型,值

所以我必须将Group,Year,Type和Sub-Type编入索引以连接多个输入表,然后在Value列上计算。

我告诉你这种情况,以防索引密集的表影响你的建议 - 我不会在这里寻求优化索引的帮助,因为已经提供了大量的建议,而且因为它是一个不同的问题!

2 个答案:

答案 0 :(得分:2)

查询优化通常更多的是艺术而不是科学,因为对结果有很多可能的影响,所以几乎没有硬性规则和快速规则。随着那个重要的警告,时间达到了高点。

索引对加载表的影响 - 索引对作为触发器的插入具有类似的性能影响。除非你有一个过滤索引,否则每个插入都必须更新表上的每个索引,所以在三个索引中你要看的是每个插入的更新数量增加四倍。对于每个插入一次读取和200k的小表大小(非常适用于表扫描),对于三个索引,您可能在黄油区域之外,因为成本与在工作台上具有这些索引的好处。

嵌套结果 - 与CTE一样,当整个结果集适合内存时,嵌套结果最有效。当部分在内存中且部分在磁盘上时,它通常比没有索引的类似大小的临时表表现更差。在5个左右的列中,对于200k行,具有较小的数据类型和现代服务器,只要您一次只设置一个结果集,就可以在嵌套查询中表现出色。再一次,这取决于你的设置,如果你被绑在一边将它们放入临时表中。

连接 - 使用临时表/嵌套查询的另一个可能的好理由是避免过大的连接。连接过程的第一步是表之间的完整笛卡尔连接,然后根据on和where子句对其进行过滤。 Join流程在所有RDMS中都经过了大量优化,所以大多数时候你都不知道幕后会发生多少繁重的工作,但是当表格达到大尺寸时,这可能是一个主要的性能难点。因此,您需要从两个表中选择所需的数据子集,并加入两个小得多的集合。子集和全表连接之间的黄油区域再次取决于许多因素,因此您必须使用查询来查找适合您情况的位置。

不幸的是,如果没有一些样本输入和输出和/或执行计划,我真的无法给出具体建议,但我希望这是一些值得思考的问题。祝你好运。

答案 1 :(得分:0)

听起来你的子查询中的数据集超过了几千行,所以我先从方法A开始,将一些中间结果集保存到#temptables,检查这些表上扫描的执行计划,以及如果需要,请索引#temptables。

如果你想使用方法B,或混合A和B,我建议尽可能使用CTE而不是嵌套查询。它们更具可读性,在测试/设计查询时更容易切换到#temptables。