Sql 两个CTE上的内部连接&x27;这需要很长时间
我正在使用productiondatabase,我需要将我的资源重新安排到多个CTE中,以便获得与我的数据匹配的正确格式 这导致Sql 两个CTE上的内部连接&x27;这需要很长时间,sql,sql-server,performance,join,Sql,Sql Server,Performance,Join,我正在使用productiondatabase,我需要将我的资源重新安排到多个CTE中,以便获得与我的数据匹配的正确格式 这导致CTE1大约有7000条记录(需要几秒钟),而CTE2大约有55000条记录(不到一秒钟) 下一步是基于两列连接两个CTE。这一步骤耗时19分钟,CTE2限制在前1000名!因为这些是CTE,所以没有一个索引。我的问题是,我怎样才能在一个合适的时间内完成这场比赛(哪怕一两分钟就足够了) CTE1由四个字母数字列组成,最多8个字符。 CTE2由三个字母数字列组成,最多8个
CTE1
大约有7000条记录(需要几秒钟),而CTE2
大约有55000条记录(不到一秒钟)
下一步是基于两列连接两个CTE。这一步骤耗时19分钟,CTE2限制在前1000名!因为这些是CTE,所以没有一个索引。我的问题是,我怎样才能在一个合适的时间内完成这场比赛(哪怕一两分钟就足够了)
CTE1由四个字母数字列组成,最多8个字符。
CTE2由三个字母数字列组成,最多8个字符和两个日期时间。
内部联接
在CTE1
的2个字母数字列上与CTE2
的2个字母数字列相匹配
示例CTE1(7000条记录)
- 列
A
有两个不同的值,与CTE2.A
中的不同值相匹配
- 列
B
大约有6500个distincts。并非所有值都在CTE2.B
中表示
示例CTE2(55000条记录)
- 列
A
有两个不同的值,与CTE1.A
中的不同值相匹配
- 列
B
大约有2000个字符。并非所有值(尽管大多数)都在CTE1.B
中表示
查询(查询CTE2前1000名需要19分钟)
在非索引数据上有TOP n
而没有ORDER BY
可能是一个问题
您还可以尝试使用以下命令“强制”列B上的联接优先级
SELECT CTE1.C
,CTE1.D
,CTE2.B
,CTE2.C
,CTE2.D
,CTE2.E
FROM CTE1
LEFT OUTER JOIN CTE2 ON CTE1.B = CTE2.B
WHERE CTE1.A = CTE2.A
AND NOT CTE2.B IS NULL
这里的问题是,尽管您的CTE各自都表现良好,但当您加入它们时,您不仅仅是说将CTE1的结果加入CTE2的结果,而是加入了两个查询定义,因此在加入到一起之前,每个查询定义都不会以其自身的方式执行,SQL Server将找到它认为是将这两个查询连接在一起的最佳方式,有时,它会导致不寻常的、非最佳的执行计划
对于CTE,有一个相当于NOEXPAND
的提示,因此您告诉优化者不要扩展定义。但是,如果您不想扩展定义,在我看来,这与使用临时表是一样的(除了不能在视图中使用临时表),因此我认为这可能是您最好的解决方法,而不是使用两个CTE,而是使用两个临时表并将它们连接在一起
或者,您可以自行仔细检查两个CTE的执行计划,并与两个CTE的执行计划进行比较,找出所有额外成本的来源、不再使用的指标等,但是如果没有你的执行计划,我甚至无法猜测问题是什么。这是对加雷斯答案的扩展
SQL Server不会单独执行CTE,然后在最终查询中合并它们。这是一个已知的问题,并且存在一个查询提示请求,该查询提示将强制实现CTE。你可以就这个请求投票
相反,它将CTE作为代码,填充到查询中,然后“优化”整个过程。对于长而复杂的查询,它可能会出错
影响性能的最常见错误是将连接更改为没有定义索引的嵌套循环连接。您可以通过查看执行计划来了解这是否正在发生。如果它包含嵌套循环,那么您可能会遇到麻烦
如果是这样,请尝试使用选项(散列连接、合并连接)运行查询
,以避免嵌套循环连接。我已经检查了接受的答案,因为我找到了一种非常简单的方法来处理我的问题(请参阅我的答案),尽管这可能不是最合适的方法。
A | B | C | D | E
---------------------------------------------------------------------------
ABC | 123 | XYZ | 2013-10-11 15:00:00.000 | 2013-10-11 16:00:00.000
SELECT CTE1.C
,CTE1.D
,CTE2.B
,CTE2.C
,CTE2.D
,CTE2.E
FROM CTE1
INNER JOIN CTE2 ON CTE1.A = CTE2.A
AND CTE1.B = CTE2.B
SELECT CTE1.C
,CTE1.D
,CTE2.B
,CTE2.C
,CTE2.D
,CTE2.E
FROM CTE1
LEFT OUTER JOIN CTE2 ON CTE1.B = CTE2.B
WHERE CTE1.A = CTE2.A
AND NOT CTE2.B IS NULL