Dav*_*vid 36 performance sql-server optimization execution-plan query-performance
对于我尝试优化的中等复杂查询,我注意到删除TOP n子句会更改执行计划。我猜想,当查询包含TOP n数据库引擎时,会运行查询而忽略该TOP子句,然后最后将结果集缩小到请求的n行数。图形执行计划似乎表明情况确实如此——TOP是“最后”一步。但似乎还有更多事情发生。
我的问题是,TOP n 子句如何(以及为什么)影响查询的执行计划?
这是我的情况的简化版本:
查询匹配来自两个表 A 和 B 的行。
如果没有该TOP子句,优化器估计将有来自表 A 的 19k 行和来自表 B 的 46k 行。返回的实际行数是 A 的 16k 和 B 的 13k。哈希匹配用于连接这两个结果集总共 69 行(然后应用排序)。此查询发生得非常快。
当我添加TOP 1001优化器时不使用哈希匹配;相反,它首先对表 A 的结果进行排序(与 19k/16k 相同的估计值/实际值)并对表 B 执行嵌套循环。表 B 的估计行数现在为 1,奇怪的是TOP n直接影响对 B 的估计执行次数(索引搜索) - 它似乎总是2n+1,或者在我的情况下是 2003 年。如果我改变,这个估计会相应地改变TOP n。当然,由于这是嵌套连接,因此实际执行次数为 16k(表 A 中的行数),这会减慢查询速度。
实际场景有点复杂,但这捕获了基本思想/行为。两个表都使用索引查找进行搜索。这是 SQL Server 2008 R2 企业版。
Pau*_*ite 40
我猜想,当查询包含 TOP n 时,数据库引擎将运行查询而忽略 TOP 子句,然后最后将结果集缩小到请求的 n 行数。图形执行计划似乎表明情况确实如此——TOP 是“最后”一步。但似乎还有更多事情发生。
上面的表述方式让我认为您可能对查询的执行方式有一个不正确的心理图景。查询计划中的运算符不是步骤(其中上一步的完整结果集由下一个步骤评估。
SQL Server 使用流水线执行模型,其中每个运算符公开Init()、GetRow()和Close() 等方法。正如GetRow()名称所暗示的那样,操作符一次按需生成一行(根据其父操作符的要求)。这在联机丛书中的逻辑和物理运算符参考中进行了记录,在我的博客文章为什么查询计划向后运行中有更多详细信息。这种一次一行的模型对于形成查询执行的合理直觉至关重要。
我的问题是,
TOPn 子句如何(以及为什么)影响查询的执行计划?
一些逻辑操作(如TOP、半连接和FAST n 查询提示)会影响查询优化器对执行计划替代方案的成本方式。基本思想是,一个可能的计划形状可能比优化为返回所有行的不同计划更快地返回前n行。
例如,索引嵌套循环连接通常是返回少量行的最快方法,尽管散列或合并连接与扫描在较大的集合上可能更有效。查询优化器对这些选择进行推理的方式是在操作逻辑树中的特定点设置行目标。
行目标修改查询计划备选方案的成本方式。它的本质是优化器首先计算每个运算符的成本,就好像需要完整的结果集一样,在适当的点设置行目标,然后返回计划树,估计它期望需要检查的行数达到行目标。
例如,逻辑TOP(10)在逻辑查询树中的特定点将行目标设置为 10。导致行目标的运算符的成本被修改以估计他们需要产生多少行来满足行目标。此计算可能会变得复杂,因此通过完整的示例和带注释的执行计划更容易理解所有这些。行目标可以影响的不仅仅是连接类型的选择,或者搜索和查找是否比扫描更受欢迎。更多细节在这里。
与往常一样,根据行目标选择的执行计划取决于优化器的推理能力和提供给它的信息质量。并非每个具有行目标的计划在实践中都会更快地生成所需数量的行,但根据成本计算模型,它会更快。
在行目标计划证明不是更快的情况下,通常有一些方法可以修改查询或向优化器提供更好的信息,以便自然选择的计划是最好的。哪个选项适合您的情况取决于课程的细节。行目标功能通常非常有效(尽管在并行执行计划中使用时需要注意一个错误)。
您的特定查询和计划可能不适合在此处进行详细分析(如果您愿意,请务必提供实际的执行计划),但希望此处概述的想法能让您取得进展。
Rob*_*ley 12
当您使用 TOP 时,优化器会看到减少工作量的机会。如果您要求 10 行,那么很有可能它不需要消耗整个集合。因此可以将 TOP 运算符进一步向右推。它将继续从下一个操作员(在其右侧)请求行,直到收到足够的行。
您指出如果没有 TOP,查询会在最后对数据进行排序。如果引擎可以提前知道连接将满足多少行,它很可能会选择使用类似的计划,将 TOP 定位在左侧。但是由于进行哈希匹配的工作量相对较高,并且可能没有合并连接的选项,优化器可能更喜欢将 TOP 进一步过滤到右侧。
当查询表 B 时,它一次获取一行。这就是估计值为 1 的原因。它还假设它只会在 50% 的时间内找到该行。所以它猜测需要 2n+1 次才能找到它。
| 归档时间: |
|
| 查看次数: |
11074 次 |
| 最近记录: |