为什么以下查询要快得多?
查询1:
select distinct ID mid
INTO #t1
from A_Position a where a.situationdate=@SituationDate and
a.Portfolio_Name=@portfolio and a.Purpose=@purpose and ID!='TOTAL'
select distinct ID gid
INTO #t2
from B_Position a where a.situationdate=@SituationDate and
a.Purpose=@purpose
select @check=COUNT(mid) from #t1 A INNER JOIN #t2 B ON A.mid =
B.gid
查询1比查询2快得多。
查询2:
;With
A as (
select distinct ID mid
from A_Position a where
a.situationdate=@SituationDate and a.Portfolio_Name=@portfolio and
a.Purpose=@purpose and ID!='TOTAL'),
B as(
select distinct ID gid
from B_Position a where
a.situationdate=@SituationDate and a.Purpose=@purpose)
select @check=COUNT(mid) from A INNER JOIN B ON A.mid =
B.gid
查询3:
select @check=COUNT(*)
from (
select distinct ID mid
from A_Position a where a.situationdate=@SituationDate and
a.Portfolio_Name=@portfolio and a.Purpose=@purpose and
ID!='TOTAL') A
inner join ( select distinct ID gid
from B_Position a where
a.situationdate=@SituationDate and a.Purpose=@purpose) B on mid=gid
基本上,所有三个查询都具有相同的结果,但是查询1只需1-2秒即可执行。另一方面,查询2或3则需要10多分钟才能执行。为什么在编写代码的方式上有如此巨大的差异? (为什么“使用”较慢)
答案 0 :(得分:1)
这是一个优化问题。如果查看执行计划,您会明白为什么其中一个比其他计划快得多。
首先,后两个相同。将子查询表示为CTE或子查询不会更改SQL Server中的执行计划。
为什么临时表版本更快?简单的答案是,它可以获得更好的执行计划。
但这就是问题。原因是由于用于连接两个表的算法。在CTE /子查询版本中,SQL Server必须猜测生成了多少行。根据这个数字,它选择认为最佳的算法。
在临时表版本中,数据已经在表中,因此SQL Server无需猜测。
因此,临时表可以产生更好的执行计划。让我告诫一些事情。使用临时表会产生更多开销-数据实际上需要存储在某个地方。它还限制了优化的可能性(在这种情况下碰巧会很好,但在其他情况下可能不会)。
您应该能够添加提示以加快其他版本的运行。我猜像是OPTION (HASH JOIN)
之类的东西。
您也许还可以设置索引来优化所有三个版本。
答案 1 :(得分:0)
答案很可能与以下事实有关:第一个查询实际上是三个查询,而其他两个只是一个查询。不过,您需要查看执行计划以进行确认。
上面的第二个和第三个查询已经提前弄清楚了执行两个子集的内部联接的最佳方法是什么。但是他们当时不知道这些子集中有多少数据,所以他们有了猜测,在这种情况下,看起来好像他们猜错了,然后选择了一种非常糟糕的方法。可能已经决定先加入然后进行筛选,或者使用索引或其他方法会更快。如果您查看执行计划,请查找预期行与实际行完全不同的位。
第一个查询将两个子集作为单独的查询放入临时表中。到进行连接时,它确切知道它要担心多少数据,并且可以选择最佳方法来处理它。
答案 2 :(得分:0)
可能是A_Position.situationdate
,A_Position.Portfolio_Name
,A_Position.Purpose
,B_Position.situationdate
和B_Position.Purpose
未编入索引的情况。
将数据子集选择到临时表中可能会减少A_Position
和B_Position
上所需表扫描的次数,并从物理上限制最终查询的数据,从而使最终查询非常快。尤其是如果表A_Position
和B_Position
包含很多记录,而临时表包含很少的记录。
我个人更愿意在上述五个字段上创建索引,并改用CTE解决方案。如果数据索引正确,那也应该非常快...
如果已经为这五个字段建立了索引,您可能需要调查执行计划,原因是优化器如此糟糕。也许应该重建索引。