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 (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' 那么它回复得很快。我的查询有什么问题需要这么多时间?

4

3 回答 3

2

性能调优不仅仅是拨动一个神奇的开关——这是一项艰苦的工作。

所以从最明显的开始:尝试将您的查询减少到绝对最低限度。

例如

  • 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 

在第二种情况下,您需要EmailIDJOIN 和EmailCM输出中的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.tblCMEvalEmailEmailSenderEMail列的索引吗?你有一个dbo.tblCMEvalEmailInfo包含两列的索引EMailID, EMailCM吗?

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

于 2013-06-02T08:19:41.590 回答
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
于 2013-06-02T08:20:13.997 回答
0

正如 marc_s 指出的那样,优化不是一件快速的事情,也不是一个一劳永逸的解决方案。最好的办法是阅读该主题(有关一些入门技巧,请参阅http://beginner-sql-tutorial.com/sql-query-tuning.htm)。

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

刚开始,我突然想到的两件事是:

  1. 您是否在用于加入的所有 ID 上设置了索引?如果没有,这将对性能产生负面影响
  2. TCMEvalEmail.EmailStatus='Success' 是一个字符串匹配,通常比较慢;没有看到解释计划的结果很难说,但你可能想考虑用数字状态代码(例如状态表的外键)替换它 - 但由于这可能是一项艰巨的任务,你应该只做如果解释计划将其作为一个问题突出显示。
于 2013-06-02T08:48:47.980 回答