DISTINCT的超慢执行计划,不确定为什么

时间:2019-01-21 22:49:56

标签: sql sql-server

版本:SQL Server 2014 Enterprise。

我有一个复杂的查询,该查询返回3 integer columns - 428 rows in total。其中一些行是重复的(所有3列都匹配)。结果以 millisecs 返回。

如果我使用SQL distinct关键字,它将以 7秒为代价返回2行的正确结果。

如果我使用CTEDISTINCT中将原始查询的执行计划与CTE隔离开-仍然是 7秒。为什么?

如果我将428 rows of results放在3列的空表中并运行select distinct c1, c2, c3 from newtable,我将在milliseconds中获得正确的2行。

所以我的问题是:

  1. 为什么DISTINCT会根本改变执行计划,为什么在查询的所有其他方面都完成之后不仅仅处理行?

2-如何在没有millisecs的情况下在DISTINCT中用SQL区分结果?

附录:原始查询无明显区别:

SELECT 
    coopterm0_.id AS x0_0_, coopterm0_.jobPostingTerm AS x1_0_, 
    coopterm0_.currentJobSearchTerm AS x2_0_ 
FROM 
    coop_term coopterm0_, 
    np_posting nposting1_ 
WHERE 
    (coopterm0_.jobPostingTerm = nposting1_.term) 
    AND (nposting1_.status IN (4, 6)) 
    AND (nposting1_.term IS NOT NULL) 
    AND (nposting1_.term IN (391, 392, 393, 410, 411, 412, 413, 415, 416 )) 
    AND ((( nposting1_.dateLastSaved >= '2019-01-20 16:00:00') 
          OR (EXISTS (SELECT napplication2_.id 
                      FROM np_application napplication2_ 
                      WHERE (napplication2_.job = nposting1_.id) 
                        AND (napplication2_.dateApplied >= '2019-01-20 16:00:00')))  
          OR (EXISTS (SELECT npostingview3_.id 
                      FROM np_posting_view npostingview3_ 
                      WHERE (npostingview3_.posting = nposting1_.id) 
                        AND (npostingview3_.dateViewed >= '2019-01-20 16:00:00')))))

运行这两个命令将执行时间减少到2秒,但仍慢了1000倍,而没有明显差异:更新统计信息np_posting_view WITH FULLSCAN;使用fullscan更新统计信息np_application;

不同的执行计划(慢):brentozar.com/pastetheplan/?id=BkQrhRXm4不明显(快速):brentozar.com/pastetheplan/?id=HJYdnA7mE

1 个答案:

答案 0 :(得分:0)

首先使用变量代替常量来测试您的查询。它给出了更真实的执行计划,并提供了实际执行计划。

IMO,您的查询未正确编写,因此Optimizer无法创建恒定或更好的计划来执行查询。

在CTE或Distinct情况下,不清楚查询内容,因为这取决于查询条件。

您必须注意到np_posting nposting1_的谓词在您的一个查询中正在多次评估。

原因之一是由于Bracket。查询中的括号组错误。

括号影响Optimizer评估Predicate的方式。

如果np_posting nposting1的结果集很小,则将它们放在CTE中,否则将它们放入Temp表中。

  

如何在不使用DISTINCT的情况下以毫秒为单位区分SQL中的结果?

您可以避免使用Distinct运算符,因为不同运算符的成本始终很高。 Distinct operator:首先获取所有行,然后消除重复的行。 Group BY:它将从头开始删除重复的行。

尝试一下,

DECLARE @Date datetime='2019-01-20 16:00:00'

With CTE AS(
SELECT term ,id
FROM np_posting nposting1_ 
WHERE ( nposting1_.status IN(4, 6)
 AND 
nposting1_.term IS NOT NULL AND  nposting1_.term IN ( 391, 392, 393, 410, 411, 412, 413, 415, 416 )  
AND  nposting1_.dateLastSaved >= @Date )
OR 
( EXISTS ( SELECT napplication2_.id FROM np_application napplication2_ WHERE  napplication2_.job = nposting1_.id  
AND  napplication2_.dateApplied >= @Date  ) )
OR 
( EXISTS ( SELECT npostingview3_.id FROM np_posting_view npostingview3_ 
WHERE  npostingview3_.posting = nposting1_.id  AND  npostingview3_.dateViewed >= @Date  ) ) 
)

SELECT  coopterm0_.id AS x0_0_, coopterm0_.jobPostingTerm AS x1_0_, coopterm0_.currentJobSearchTerm AS x2_0_ 
FROM coop_term coopterm0_
inner join  CTE nposting1_ 
on  coopterm0_.jobPostingTerm = nposting1_.term  
group by coopterm0_.id,coopterm0_.jobPostingTerm,coopterm0_.currentJobSearchTerm