Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 两个CTE上的内部连接&x27;这需要很长时间_Sql_Sql Server_Performance_Join - Fatal编程技术网

Sql 两个CTE上的内部连接&x27;这需要很长时间

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个

我正在使用productiondatabase,我需要将我的资源重新安排到多个CTE中,以便获得与我的数据匹配的正确格式

这导致
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