避免SQL Server上急切的spool操作的方法

41

我有一个ETL流程,其中涉及到一个存储过程,该存储过程大量使用SELECT INTO语句(最小化记录,因此比生成更少的日志流量更快)。在一个特定的存储过程中进行的一批工作中,几个最昂贵的操作是急切的占位符,它们似乎只是缓冲查询结果,然后将它们复制到所制作的表中。

有关急切的占位符的MSDN文档非常简单。是否有人更深入地了解这些东西是否真的有必要(以及在什么情况下)?我有一些可能有或没有意义的理论,但没有成功地将它们从查询中剔除。

因此,以下是一些可能可分解为具体答案的理论:

  • 查询使用一些UDF进行数据转换,例如解析格式化日期。这种数据转换是否需要使用急切的占位符来分配合理的类型(例如varchar长度)到表中,在它构建表之前?
  • 作为上述问题的延伸,是否有人对驱动查询中的此操作具有更深入的了解?
1个回答

35

我对spooling的理解是,它在你的执行计划中有点像一个误导。是的,它占了很大一部分的查询成本,但实际上它是SQL Server自动进行的优化,以避免昂贵的重新扫描。如果你避免使用spooling,那么它所在的执行树的成本将会上升,几乎可以肯定整个查询的成本也会增加。我并没有特别深入地研究数据库查询优化器在什么情况下会解析成这样,尤其是没有看到SQL代码的情况下,但你最好相信它的行为。

然而,这并不意味着你的执行计划不能被优化,这取决于你具体在做什么以及你的源数据的易变性。当你执行SELECT INTO时,你经常会在执行计划中看到spooling项,它可能与读取隔离级别有关。如果适用于你的特定情况,你可以尝试将事务隔离级别降低到更少成本的级别,并/或使用NOLOCK提示。在复杂的性能关键型查询中,即使在看起来没有任何原因的情况下,如果安全且适合你的数据,NOLOCK也可以大幅提高查询执行的速度。

在这种情况下,如果你尝试使用READ UNCOMMITTEDNOLOCK提示,你可能能够消除一些spooling。(显然,如果这可能使你处于不一致的状态,你不想这样做,但每个人的数据隔离要求都是不同的)。TOP操作符和OR操作符有时会导致spooling,但我怀疑你在ETL过程中并没有使用它们......

你说得对,你的UDF也可能是罪魁祸首。如果你每个UDF只使用一次,将它们放在内联中以查看是否获得了巨大的性能收益,这将是一个有趣的实验。(如果你无法想出一种方法将它们与查询一起编写,那么它们可能是造成spooling的原因)。

最后一个我会看的是,如果你正在执行任何可以重新排序的连接,请尝试使用提示来强制连接顺序按照你知道的最具选择性的顺序进行。这有点困难,但如果你已经卡在优化上,尝试一下也无妨。


读取隔离可能适用于从源复制的暂存区域查询的过程。此外,即使这不能解决我的特定问题,它也增加了一些见解,因为在任何MSDN文献中都没有提到急切的占位符操作。 - ConcernedOfTunbridgeWells
很高兴能够提供帮助。如果您发布有关问题的SQL代码(当然需要进行泛化处理),我们可能会进一步为您提供帮助。 - Grank
急切的缠线(Eager spools)也不如懒惰的缠线(Lazy spools)。我没有关于如何将您的急切转为懒惰的实质性建议,但只处理一小部分数据并将其完全传递到管道中的概念提出了一种备选方法:将工作分批处理成每次1000或10000行的较小片段。要设计一个良好的“步进”方案,让您能够快速地按块遍历集群索引是相当费力的,但结果可能会令人震撼... - ErikE
谢谢你在这里提到TOP运算符 - 对我来说,它是EXISTS子句中的问题。 - JleruOHeP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接