使用datediff函数进行慢速T-SQL查询

时间:2017-02-13 01:55:05

标签: sql sql-server tsql

我有一个查询,当日期条款"和datediff(day,con2.DT_DateIncluded),' 2017-01-01')< = 0"在下面的代码中没有在查询中使用,但在包含它时运行缓慢。虽然当我只运行部件时运行速度很快,但选择前2个ID_Contact ...",甚至包括date子句。我在经典ASP应用程序上有这个查询,它无法转换为存储过程(项目范围原因)。您能否通过更改查询代码帮我找到改善完整查询性能的方法?

select distinct top 10 
    ID_Contact, NO_CodCompany 
from 
    tblContacts con1 
where 
    ID_Contact in (select top 2 ID_Contact
                   from tblContacts con2 
                   inner join tblCompanies cp on con2.NO_CodCompany = cp.ID_Company
                   where con2.NO_CodCompany = con1.NO_CodCompany
                     and datediff(day, con2.DT_DateIncluded), '2017-01-01') <= 0)

3 个答案:

答案 0 :(得分:1)

这基本上是您的查询: 这是您的查询:

select distinct top 10 ID_Contact, NO_CodCompany
from tblContacts con1
where ID_Contact in (select top 2 ID_Contact
                     from tblContacts con2 inner join
                          tblCompanies cp
                          on con2.NO_CodCompany = cp.ID_Company
                     where con2.NO_CodCompany = con1.NO_CodCompany and
                           datediff(day, con2.DT_DateIncluded), '2017-01-01') <= 0
                    );

我的第一个建议是将datediff()更改为简单的日期比较:

select distinct top 10 ID_Contact, NO_CodCompany
from tblContacts con1
where ID_Contact in (select top 2 ID_Contact
                     from tblContacts con2 inner join
                          tblCompanies cp
                          on con2.NO_CodCompany = cp.ID_Company
                     where con2.NO_CodCompany = con1.NO_CodCompany and
                           con2.DT_DateIncluded < '2017-01-02'
                    );

然后,我将删除子查询中的JOIN。我不是100%确定这完全等同,因为这可能取决于数据中的细微差别:

select distinct top 10 ID_Contact, NO_CodCompany
from tblContacts con1
where con1.ID_Contact in (select top 2 con2.ID_Contact
                          from tblCompanies cp
                          where con1.NO_CodCompany = cp.ID_Company and
                                con1.DT_DateIncluded < '2017-01-02' 
                         );

然后,如果您可以删除最外层查询中的select distinct,则应该这样做。

答案 1 :(得分:1)

请改为尝试:

con2.DT_DateIncluded < '20170102'

它更好,因为它仍然允许服务器使用DT_DateIncluded列上的任何索引。目前,这是不可能的。更糟糕的是,查询可能不得不在表中的每条记录上运行DATEDIFF()函数。

请注意,此 等同于您发布的内容,即使它可能与您的预期不符。我怀疑con2.DT_DateIncluded < '20170101'更接近你的真实含义。

我还怀疑你可以在没有tblContacts的第二个实例或使用窗口函数来获得更好的结果,或者至少使用JOIN而不是IN来过滤结果。

最后,由于历史原因,在输入仅限日期的值时,您应该使用 unseparated 日期格式,如下所述:

  

The ultimate guide to the datetime datatypes

对于日期/时间值,您仍然可以使用您习惯的分隔yyyy-mm-dd hh:mm:ss,但如果您只有日期部分,则yyyymmdd会更好。

基于此评论:

  

此查询的目标是从公司获取联系人,但每家公司只能使用“n”个联系人

您应该查看APPLY运算符。遗憾的是,我仍然不清楚所有内容是如何组合在一起的,但我最少会使用APPLY运算符来演示每个公司的两个联系人,您可以将其作为起点:

SELECT TOP 10 ct.ID_Contact, ct.NO_CodCompany
FROM tblCompanies cp
CROSS APPLY (
    SELECT TOP 2 ID_Contact, NO_CodCompany
    FROM tblContacs 
    WHERE NO_CodCompany = cp.ID_Company
        AND DT_DateIncluded < '20170102'
    ORDER BY DT_DateIncluded DESC
) ct

APPLY类似于JOIN嵌套SELECT查询,其中没有ON子句;相反,join条件作为嵌套WHERE语句中SELECT子句的一部分包含在内。

请注意CROSS的使用。这将排除完全没有联系的公司。如果要包含这些公司,请将其更改为OUTER

您还应该查看已定义的索引。查看tblContactsNO_CodCompany(按此顺序!)的DT_DateIncluded表上的单个索引可能会为此查询创建奇迹,尤其是如果它在ID_Contact中也有INCLUDES tblContacts条款。然后,您可以完全从索引中完成查询的int a[]; int a[2]; //OK 部分。

答案 2 :(得分:1)

而不是`DATEDIFF()&lt; 0&#39;尝试使用:

and con2.DT_DateIncluded <= '2017-01-01' 

另外,确保`DT_DateIncluded&#39;上有一个索引。柱。

DATEDIFF()运行缓慢的原因是使用它需要一些时间来执行计算,查询优化器(可能)最终为整个表运行它,并且(可能)没有索引帮助它选择所需的行。

当您删除该子句时,查询运行得更快,但这可能有助于您只选择内部查询中的前两行和外部查询中的十行,从而允许进行表扫描足够高效。