查询执行需要花费太多时间

时间:2013-06-02 08:09:18

标签: sql sql-server-2008

我有以下查询

SELECT dbo.tblRegion.RegionName,
       dbo.tblDistributionLocation.DistributionLocationName,
       dbo.tblTSA.TSAName,
       TEmailInfo.EmailCM,
       COUNT(*) AS EmailCount
FROM   dbo.tblArea
       INNER JOIN dbo.tblTerritory
         ON dbo.tblArea.AreaID = dbo.tblTerritory.AreaID
       INNER JOIN dbo.tblDistribution
         ON dbo.tblTerritory.TerritoryID = dbo.tblDistribution.TerritoryID
       INNER JOIN dbo.tblDistributionLocation
         ON dbo.tblDistribution.DistributionID = dbo.tblDistributionLocation.DistributionID
       INNER JOIN dbo.tblRegion
         ON dbo.tblArea.RegionID = dbo.tblRegion.RegionID
       INNER JOIN dbo.tblTSA
         ON dbo.tblDistributionLocation.DistributionLocationID = 
                                                       dbo.tblTSA.DistributionLocationID
       INNER JOIN dbo.tblTSAEmail
         ON dbo.tblTSA.TSAID = dbo.tblTSAEmail.TSAID
       INNER JOIN (SELECT *
                   FROM   dbo.tblCMEvalEmail
                   WHERE  ( dbo.tblCMEvalEmail.EmailSentDate 
                    BETWEEN '2013-05-19 00:00:00' AND '2013-06-16 23:59:59' )) AS TCMEvalEmail
         ON dbo.tblTSAEmail.TSAEmail = TCMEvalEmail.EmailSenderEmail
       INNER JOIN (SELECT *
                   FROM   dbo.tblCMEvalEmailInfo
                   WHERE  dbo.tblCMEvalEmailInfo.EmailCMFacingDate 
                    BETWEEN '2013-05-19 00:00:00' AND '2013-06-16 23:59:59') AS TEmailInfo
         ON TCMEvalEmail.EmailID = TEmailInfo.EmailID
WHERE  ( dbo.tblTSA.TSAActive = 1 )
       AND TCMEvalEmail.EmailStatus = 'Success'
GROUP  BY dbo.tblRegion.RegionName,
          dbo.tblDistributionLocation.DistributionLocationName,
          dbo.tblTSA.TSAName,
          TEmailInfo.EmailCM 

这个查询有什么问题需要花费很多时间?

但如果我缩短'2013-05-20 00:00:00'和'2013-06-16 23:59:59'的时间,那么它回复得那么快。我的查询有什么问题需要花费这么多时间?

3 个答案:

答案 0 :(得分:2)

性能调整不只是翻转魔术开关 - 这很难。

首先从最明显的开始:尝试将查询减少到绝对最小值。

E.g。

  • 当您只使用该数据中的一个(或两个)列时,为什么在内部查询中选择SELECT *?只选择真正需要的

在第一种情况下,如果我没有弄错,你只需要EmailSenderEMail列 - 所以只选择那个!

INNER JOIN 
(
   select EmailSenderEmail 
   from dbo.tblCMEvalEmail 
   where (dbo.tblCMEvalEmail.EmailSentDate BETWEEN '2013-05-19 00:00:00' 
                                               AND '2013-06-16 23:59:59') 
) as TCMEvalEmail  ON dbo.tblTSAEmail.TSAEmail = TCMEvalEmail.EmailSenderEmail 

在第二种情况下,您需要加入EmailIDEmailCM的输出中需要SELECT - 所以只选择这两列!

INNER JOIN 
(
    select EMailID, EMailCM
    from dbo.tblCMEvalEmailInfo 
    where dbo.tblCMEvalEmailInfo.EmailCMFacingDate BETWEEN '2013-05-19 00:00:00' 
                                                       and '2013-06-16 23:59:59'
 ) as TEmailInfo ON TCMEvalEmail.EmailID = TEmailInfo.EmailID 
  • 下一步:确保您有适当的索引。如果你有这样的子选择,那么拥有一个覆盖你的查询的索引是非常有价值的,例如:这将完全返回您需要的列。那么,dbo.tblCMEvalEmail列的EmailSenderEMail列上有索引吗?您是否在dbo.tblCMEvalEmailInfo上有一个包含两列EMailID, EMailCM的索引?

  • 另一件事:所有外键列都应编入索引,以提高JOIN操作的速度,并帮助加快外键约束检查。你在这里使用的外键都是索引的吗?

答案 1 :(得分:0)

可能没有适当的索引来进行连接。您可以优化这两个子选择,但我怀疑查询优化器已经这样做了。

SELECT dbo.tblRegion.RegionName, 
        dbo.tblDistributionLocation.DistributionLocationName, 
        dbo.tblTSA.TSAName,
        TEmailInfo.EmailCM,
        COUNT(*) as EmailCount
FROM dbo.tblArea 
INNER JOIN dbo.tblTerritory
 ON dbo.tblArea.AreaID = dbo.tblTerritory.AreaID
INNER JOIN dbo.tblDistribution
 ON dbo.tblTerritory.TerritoryID = dbo.tblDistribution.TerritoryID
INNER JOIN dbo.tblDistributionLocation
 ON dbo.tblDistribution.DistributionID = dbo.tblDistributionLocation.DistributionID 
INNER JOIN dbo.tblRegion
 ON dbo.tblArea.RegionID = dbo.tblRegion.RegionID 
INNER JOIN dbo.tblTSA
 ON dbo.tblDistributionLocation.DistributionLocationID = dbo.tblTSA.DistributionLocationID 
INNER JOIN dbo.tblTSAEmail
 ON dbo.tblTSA.TSAID = dbo.tblTSAEmail.TSAID 
INNER JOIN dbo.tblCMEvalEmail
 ON dbo.tblTSAEmail.TSAEmail = tblCMEvalEmail.EmailSenderEmail
   AND dbo.tblCMEvalEmail.EmailSentDate BETWEEN '2013-05-19 00:00:00' 
                                               AND '2013-06-16 23:59:59'
   AND tblCMEvalEmail.EmailStatus='Success'
INNER JOIN dbo.tblCMEvalEmailInfo
 ON tblCMEvalEmail.EmailID = tblCMEvalEmailInfo.EmailID
   AND dbo.tblCMEvalEmailInfo.EmailCMFacingDate BETWEEN '2013-05-19 00:00:00' 
                                                       and '2013-06-16 23:59:59'
WHERE (dbo.tblTSA.TSAActive = 1) 
GROUP BY dbo.tblRegion.RegionName, 
          dbo.tblDistributionLocation.DistributionLocationName, 
          dbo.tblTSA.TSAName, TEmailInfo.EmailCM

答案 2 :(得分:0)

正如marc_s指出的那样,优化不是一件容易的事情,也不是一个单一的技巧 - 解决方案。您最好的选择是阅读相关主题(有关初学者提示,请参阅http://beginner-sql-tutorial.com/sql-query-tuning.htm。)

您还应该阅读EXPLAIN PLAN工具(或数据库的等效变体),这是一个至关重要的优化工具;它会突出显示可能会减慢您对特定数据库的查询速度的事情,例如全表扫描 - 消除这些通常会让您快速获胜并且通常会有明显的改进。

然而,刚开始,我跳出来的两件事是:

  1. 您是否在所有用于加入的ID上设置了索引?如果没有,这将对性能产生负面影响
  2. TCMEvalEmail.EmailStatus ='成功'是一个字符串匹配,通常是一个缓慢的比较;没有看到你的解释计划的结果很难说,但你可能想考虑用数字状态代码(例如STATUS表的外键)替换它 - 但是因为这可能是一个大任务你应该只做它如果解释计划强调它是一个问题。