为什么在联接谓词强制嵌套循环中引用变量?


16

我碰到这个问题最近,无法在网上找到的任何讨论。

下面的查询

DECLARE @S VARCHAR(1) = '';

WITH T
     AS (SELECT name + @S AS name2,
                *
         FROM   master..spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2;

始终获得嵌套循环计划

在此处输入图片说明

尝试通过INNER HASH JOININNER MERGE JOIN提示强制问题会产生以下错误。

由于此查询中定义的提示,查询处理器无法生成查询计划。重新提交查询而不指定任何提示,也无需使用SET FORCEPLAN。

我发现了一种允许使用散列或合并联接的解决方法-将变量包装在一个聚合中。生成的计划的成本大大降低(19.2025比0.261987)

DECLARE @S2 VARCHAR(1) = '';

WITH T
     AS (SELECT name + (SELECT MAX(@S2)) AS name2,
                *
         FROM   spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2; 

在此处输入图片说明

这种行为的原因是什么?有没有比我发现的更好的解决方法?(也许不需要额外的执行计划分支)

Answers:


13

我已尝试在SQL 2012实例上执行查询,但跟踪标记4199似乎可以解决此问题。启用它,我得到的合并联接的总成本为0.24,并且没有额外的分支。

此问题的特定KB文章是查询中的连接谓词在SQL Server 2005或SQL Server 2008中具有外部引用列时,会出现性能问题。

在此处输入图片说明

为了进一步合格,TF 4199启用了所有优化程序修复。有关更多信息,请参见此链接。一次启用所有功能都会产生怪异的副作用,因此,如果您可以找到特定的修复程序,则最好自己启用该修复程序。

您可以使用OPTION (QUERYTRACEON 4199),在每个查询的基础上启用跟踪标志。


0

旧的问题,但看到答案不是绝对的,以为我会发布找到的解决方法。不知道为什么查询优化器会不屑一顾HASH,但我认为它不喜欢,MERGE因为它没有对输入进行排序。在2012/14年,

DECLARE @S VARCHAR(1) = '';

    WITH T
        AS (SELECT TOP (2147483647)
                name + @S AS name2,
                *
            FROM   master..spt_values
            ORDER BY name + @S)
    SELECT *
    FROM   T T1
           INNER JOIN T T2
             ON T1.name2 = T2.name2;

产生以下计划:

在此处输入图片说明

CTE中的强制TOPORDER BY似乎为优化器提供了有关数据集的足够知识,以执行优化MERGE JOIN

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.