Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 查询执行时间太长_Sql_Sql Server 2008 - Fatal编程技术网

Sql 查询执行时间太长

Sql 查询执行时间太长,sql,sql-server-2008,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

我有以下疑问

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”的时间,那么它的回复速度会很快。我的查询花了这么多时间,有什么问题吗?

性能调整不仅仅是打开一个神奇的开关,而是一项艰巨的工作

因此,从最明显的问题开始:尽量将您的查询减少到绝对最小

例如

为什么在内部查询中选择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 
在第二种情况下,您需要用于连接的EmailID,以及SELECT的输出中的EmailCM—所以只选择这两列

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的索引吗

另一件事:所有外键列都应该被索引,以提高连接操作的速度,并帮助加快外键约束检查。您在这里使用的外键都被索引了吗


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

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

正如marc_指出的那样,优化不是一件快速的事情,也不是一个一招包换的解决方案。你最好的选择是阅读这个主题,看看一些入门技巧

您还应阅读解释计划工具或DB的等效变体,这是一个重要的优化工具;它将突出显示可能会减慢您在特定数据库上的查询速度的事情,例如全表扫描—消除这些扫描通常会给您带来快速的成功,并且通常会带来明显的改进

然而,我突然想到的两件事是:

您是否在用于加入的所有ID上设置了索引?否则,这将对性能产生负面影响 EmailStatus='Success'是一个字符串匹配,通常比较慢;如果没有看到你的解释计划的结果,很难说,但是你可能想考虑用一个数字状态代码代替一个状态表的外键,但是因为这可能是一个大的任务,如果解释计划强调它是一个问题,你应该只做它。
很好的注释,但是用必填字段替换“*”真的能提高那么多性能吗?SQL Server是否也在这样做,即优化子选择中的表读取?在子查询中选择*不是问题。SQL Server不会检索所有列,然后在以后丢弃它们,而是将子查询定义内联。e、 g.请参阅执行计划中的SELECT type FROM SELECT*FROM master..spt_值。T仅从NCI检索类型列。它不进行CI扫描。@marc_替换子选择中的*将不会产生任何影响。虽然您所说的对外部查询是正确的,但它对子选择或内部查询没有相同的影响,因为查询优化器实际上会将它们更改为外部查询中提到的字段,因此,这是一种自我优化的方法。也有可能您会返回多条记录,而您不希望它在每封电子邮件中返回超过1条记录,如果在多个表中发生这种情况,结果将变成指数级。例如,如果EmailID在tblCMEvalEmail表中不唯一,或者EmailSenderEmail在tblCMEvalEmail表中不唯一,那么这可能是加入的错误列?