为什么在这个sql中添加where语句会让它运行得慢得多?

时间:2011-03-15 12:43:32

标签: sql sql-server

我继承了一个存储过程并且遇到问题需要很长时间才能运行(大约3分钟)。我玩过它,没有where子句它实际上只需要12秒就可以运行。它引用的表中都没有大量数据,任何人都可以看到为什么在下面添加main where子句需要更长的时间?

ALTER Procedure [dbo].[MissingReadingsReport] @SiteID    INT,
                                              @FormID    INT,
                                              @StartDate Varchar(8),
                                              @EndDate   Varchar(8)
As
  If @EndDate > GetDate()
    Set @EndDate = Convert(Varchar(8), GetDate(), 112)

  Select Dt.FormID,
         DT.FormDAte,
         DT.Frequency,
         Dt.DayOfWeek,
         DT.NumberOfRecords,
         Dt.FormName,
         dt.OrgDesc,
         Dt.CDesc
  FROM   (Select MeterForms.FormID,
                 MeterForms.FormName,
                 MeterForms.SiteID,
                 MeterForms.Frequency,
                 DateTable.FormDate,
                 tblOrganisation.OrgDesc,
                 CDesc = ( COMPANY.OrgDesc ),
                 DayOfWeek = CASE Frequency
                               WHEN 'Day' THEN DatePart(dw, DateTable.FormDate)
                               WHEN 'WEEK' THEN
                               DatePart(dw, MeterForms.FormDate)
                             END,
                 NumberOfRecords = CASE Frequency
                                     WHEN 'Day' THEN (Select TOP 1 RecordID
                                                      FROM   MeterReadings
                                                      Where
                                     MeterReadings.FormDate =
                                     DateTable.FormDate
                                     And MeterReadings.FormID =
                                         MeterForms.FormID
                                                      Order  By RecordID DESC)
                                     WHEN 'WEEK' THEN (Select TOP 1 ( FormDate )
                                                       FROM   MeterReadings
                                                       Where
                                     MeterReadings.FormDate >=
                                     DateAdd(d
                                     , -4,
                                     DateTable.FormDate)
                                     And MeterReadings.FormDate
                                         <=
                                         DateAdd(d, 3,
                                         DateTable.FormDate)
                                     AND MeterReadings.FormID =
                                         MeterForms.FormID)
                                   END
          FROM   MeterForms
                 INNER JOIN DateTable
                   ON MeterForms.FormDate <= DateTable.FormDate
                 INNER JOIN tblOrganisation
                   ON MeterForms.SiteID = tblOrganisation.pkOrgId
                 INNER JOIN tblOrganisation COMPANY
                   ON tblOrganisation.fkOrgID = COMPANY.pkOrgID
          /*this is what makes the query run slowly*/
          Where  DateTable.FormDAte >= @StartDAte
                 AND DateTable.FormDate <= @EndDate
                 AND MeterForms.SiteID = ISNULL(@SiteID, MeterForms.SiteID)
                 AND MeterForms.FormID = IsNull(@FormID, MeterForms.FormID)
                 AND MeterForms.FormID > 0)DT
  Where  ( Frequency = 'Day'
           And dt.NumberofRecords IS NULL )
          OR ( ( Frequency = 'Week'
                 AND DayOfWeek = DATEPART (dw, Dt.FormDate) )
               AND ( FormDate <> NumberOfRecords
                      OR dt.NumberofRecords IS NULL ) )
  Order  By FormID  

4 个答案:

答案 0 :(得分:2)

根据您已经提到过的内容,看起来表格是为连接条件中的列正确编制索引的,而不是where子句中的列。

如果您不愿意更改查询,那么查看where子句列中定义的索引可能是值得的,特别是具有NULL检查的索引

答案 1 :(得分:0)

我愿意打赌,如果你把Meterforms的条款移到了以下声明中:

 FROM (select [columns] from MeterForms WHERE SiteID= ISNULL [etc] ) MF
      INNER JOIN [etc]

它会更快,因为过滤会在连接之前发生。此外,让你的DateTable上的INNER JOIN在你的where子句中执行&lt; = down可能会返回比你想要的更多...尝试将其移动到子选择之间。

您是否在此处运行执行计划,看看瓶颈在哪里?

答案 2 :(得分:0)

随机建议,来自Oracle背景:
如果您重写以下内容会发生什么:

AND MeterForms.SiteID = ISNULL(@SiteID, MeterForms.SiteID)
AND MeterForms.FormID = IsNull(@FormID, MeterForms.FormID)

...至

AND (@SiteID is null or MeterForms.SiteID = @SiteID)
AND (@FormID is null or MeterForms.FormID = @FormID)

答案 3 :(得分:0)

尝试用以下内容替换您的选择:

FROM   
                (select siteid, formid, formdate from meterforms 
                 where siteid = isnull(@siteid, siteid) and
                        meterforms.formid = isnull(@formid, formid) and formid >0
                 ) MeterForms
                 INNER JOIN 
                 (select formdate from datetable where formdate >= @startdate and formdate <= @enddate) DateTable
                   ON MeterForms.FormDate <= DateTable.FormDate
                 INNER JOIN tblOrganisation
                   ON MeterForms.SiteID = tblOrganisation.pkOrgId
                 INNER JOIN tblOrganisation COMPANY
                   ON tblOrganisation.fkOrgID = COMPANY.pkOrgID
          /*this is what makes the query run slowly*/ 
          )DT