我最近遇到了这个问题,但在网上找不到任何关于它的讨论。
下面的查询
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 JOIN
或INNER 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;
这种行为的原因是什么?有没有比我发现的更好的解决方法?(也许不需要额外的执行计划分支)
我已经在 SQL 2012 实例上尝试过你的查询,跟踪标志 4199 似乎可以解决这个问题。启用它后,我得到了一个合并连接,总成本为 0.24,并且没有任何额外的分支。
此问题的特定知识库文章是当查询中的连接谓词在 SQL Server 2005 或 SQL Server 2008 中具有外部引用列时出现性能问题
为了进一步限定,TF 4199 启用了所有优化器修复。有关详细信息,请参阅此链接。一次启用所有内容可能会产生奇怪的副作用,因此如果您能找到特定的修复程序,最好自行启用该修复程序。
您可以使用在每个查询的基础上启用跟踪标志
OPTION (QUERYTRACEON 4199)
;老问题,但看到答案并不是非常明确,我想我会发布我找到的解决方法。不知道为什么查询优化器会犹豫
HASH
,但我认为它不喜欢MERGE
,因为它没有排序的输入。2012/14 年度,产生以下计划:
强制
TOP
和ORDER BY
cte 中的 the 似乎为优化器提供了有关数据集的足够知识以执行MERGE JOIN
.