我正在使用一个生产数据库,我需要将我的资源重新安排到多个CTE中,以便获得与我的数据匹配的正确格式。
这导致CTE1
大约有7000条记录(需要几秒钟),CTE2
大约有55000条记录(需要不到一秒钟)。
下一步是根据两列加入两个CTE。这一步花了19分钟,CTE2限制在TOP 1000
!由于这些是CTE,因此没有一个指数。我的问题是如何在一个合适的时间内完成这场比赛(即使一两分钟就足够了)。
CTE1由四个字母数字列组成,最多包含8个字符。
CTE2由三个字母数字列组成,最多包含8个字符和两个日期时间。
inner join
对CTE1
的2个字母数字列与CTE2
的2个字母数字列进行匹配。
示例CTE1(7000条记录)
A | B | C | D
---------------------------------------------------------------------------
ABC | 123 | 1234567 | 12345678
A
有两个不同的值,匹配CTE2.A
的不同值。B
有大约6500个区别。并非所有值都在CTE2.B
。示例CTE2(55000条记录)
A | B | C | D | E
---------------------------------------------------------------------------
ABC | 123 | XYZ | 2013-10-11 15:00:00.000 | 2013-10-11 16:00:00.000
A
有两个不同的值,匹配CTE1.A
的不同值。B
有大约2000个区别。并非所有值(尽管大多数)都在CTE1.B
。查询(使用此查询,CTE2的前1000名需要19分钟)
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
答案 0 :(得分:3)
这正在扩大Gareth的答案。
SQL Server不会单独执行CTE,然后在最终查询中将它们组合在一起。这是一个已知问题,并且有一个查询提示的请求会强制实现CTE的实现。您可以对请求here进行投票。
相反,它将CTE作为代码,将它们填充到查询中,然后“优化”整个事物。对于长而复杂的查询,可能会出错。
影响性能的最常见错误是将连接更改为嵌套循环连接,其中没有定义索引。您可以通过查看执行计划来查看是否发生了这种情况。如果它包含嵌套循环,那么您可能遇到麻烦。
如果是这样,请尝试使用OPTION (HASH JOIN, MERGE JOIN)
运行查询以避免嵌套循环连接。
答案 1 :(得分:1)
问题在于,尽管你的CTE本身都表现良好,但当你加入它们时,你不只是说将CTE1的结果加入到CTE2的结果中,你加入了两个查询定义,所以每个都不是在连接在一起之前,SQL Server会自行执行,SQL Server会发现它认为是将这两个查询连接在一起的最佳方式,有时候,它不会经常导致异常且非最佳的执行计划。
有一个connect item requesting等同于CTE的NOEXPAND
提示,因此您告诉优化者不要扩展定义。如果你不想扩展定义,在我看来和使用临时表一样(除了你不能在视图中使用临时表),所以我认为这可能是你最好的工作,而不是使用两个CTE,使用两个临时表并将它们连接在一起。
或者,您可以自己仔细检查两个CTE的执行计划,并与两者的执行计划进行比较,找出所有额外成本的来源,不再使用的索引等,但是如果没有你的计划,我甚至无法开始猜测问题是什么。
答案 2 :(得分:0)
在非索引数据上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