2012-07-06 35 views
1

我想优化一个存储过程,并在查看执行计划和执行时间后,我对结果感到惊讶。任何人都可以解释。为什么我的重构SQL比原始版本效率低?

原来的SQL我写了2 几乎相同选择,我再拉在一起的CTE,我试图重构,如此的主要工作是做一次,填充表变量,所以我可以再有2个较小的选择以我需要的方式过滤数据。 2个select语句之间的唯一区别是在第一个select中传递给TVF_GetChildGroups的值@AreaID表示当前上下文的报告区域,第二个select中的@RootReportLevelID仅仅是所有区域。所以它是用户环境的同行,目的是让你的分数与其他人的平均数相比较。

DECLARE @Scores TABLE 
(
    ShortName VARCHAR(50) , 
    PCTMax INT , 
    PCTAvg INT , 
    PCTMin INT , 
    ALLAvg INT , 
    AllMax INT , 
    AllMin INT 
) 
INSERT INTO @Scores 
    SELECT T2.ShortName , 
      MAX(T1.MeridianScore) AS PCTMax , 
      CAST((CAST(SUM(T1.contribution) AS DECIMAL)/CAST(SUM(T1.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS PCTAvg , 
      MIN(T1.MeridianScore) AS PCTMin , 
      CAST((CAST(SUM(T2.contribution) AS DECIMAL)/CAST(SUM(T2.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS AllAvg , 
      MAX(T2.MeridianScore) AS AllUpperScore , 
      MIN(T2.MeridianScore) AS AllLowerScore 
    FROM (SELECT US.PKID , 
         PT.ShortName , 
         CAST((CAST(SUM(RES.contribution) AS DECIMAL)/CAST(SUM(RES.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS MeridianScore , 
         SUM(Contribution) AS Contribution , 
         SUM(MaxValue) AS MaxValue 
       FROM  tblUploadedScorecards AS US 
         INNER JOIN tblUploadedScoreCardResults AS RES ON US.PKID = RES.FKUploadedScoreCardID 
         INNER JOIN tblUploadedScorecardHeaders AS USH ON USH.FKUploadedScorecardID = US.PKID 
         INNER JOIN @ProviderTable AS PT ON USH.HeaderValue = PT.FullName 
         INNER JOIN TVF_GetChildGroups(@AreaID) AS TGCG ON TGCG.GroupName = US.Branch 
       WHERE  US.FKScoreCardID = 185 
         AND reviewed = 1 
         AND ShopDate BETWEEN @StartDate AND @EndDate 
         AND RES.Rating <> 'I' 
         AND USH.FKScorecardHeaderID = 71 
       GROUP BY US.PKID , 
         PT.ShortName) AS T1 
      RIGHT JOIN (SELECT US.PKID , 
           PT.ShortName , 
           CAST((CAST(SUM(RES.contribution) AS DECIMAL)/CAST(SUM(RES.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS MeridianScore , 
           SUM(Contribution) AS Contribution , 
           SUM(MaxValue) AS MaxValue 
         FROM tblUploadedScorecards AS US 
           INNER JOIN tblUploadedScoreCardResults AS RES ON US.PKID = RES.FKUploadedScoreCardID 
           INNER JOIN tblUploadedScorecardHeaders AS USH ON USH.FKUploadedScorecardID = US.PKID 
           INNER JOIN @ProviderTable AS PT ON USH.HeaderValue = PT.FullName 
           INNER JOIN TVF_GetChildGroups(@RootReportLevelID) AS TGCG ON TGCG.GroupName = US.Branch 
         WHERE US.FKScoreCardID = 185 
           AND reviewed = 1 
           AND ShopDate BETWEEN @StartDate AND @EndDate 
           AND RES.Rating <> 'I' 
           AND USH.FKScorecardHeaderID = 71 
         GROUP BY US.PKID , 
           PT.ShortName) AS T2 ON T1.ShortName = T2.ShortName 
    GROUP BY T2.ShortName 

所以我重构出的共性到表变量对我可以申请以后在无需打表了这么多的希望联接到TVF并结束了与此:

DECLARE @PreHierarchyResults TABLE 
(
PKID INT , 
Branch VARCHAR(150) , 
ShortName VARCHAR(50) , 
Contribution DECIMAL(20,3), 
MaxValue DECIMAL(20,3) 
) 

INSERT INTO @PreHierarchyResults 
    (PKID , 
     Branch , 
     ShortName , 
     Contribution , 
     MaxValue) 
SELECT US.PKID , 
    US.Branch , 
    PT.ShortName , 
    Contribution AS Contribution , 
    MaxValue AS MaxValue 
FROM tblUploadedScorecards AS US 
    INNER JOIN tblUploadedScoreCardResults AS RES ON US.PKID = RES.FKUploadedScoreCardID 
    INNER JOIN tblUploadedScorecardHeaders AS USH ON USH.FKUploadedScorecardID = US.PKID 
    INNER JOIN @ProviderTable AS PT ON USH.HeaderValue = PT.FullName 
WHERE US.FKScoreCardID = 185 
    AND reviewed = 1 
    AND ShopDate BETWEEN @StartDate AND @EndDate 
    AND RES.Rating <> 'I' 
    AND USH.FKScorecardHeaderID = 71 


INSERT INTO @Scores 
    SELECT T2.ShortName , 
      MAX(T1.MeridianScore) AS PCTMax , 
      CAST((CAST(SUM(T1.contribution) AS DECIMAL)/CAST(SUM(T1.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS PCTAvg , 
      MIN(T1.MeridianScore) AS PCTMin , 
      CAST((CAST(SUM(T2.contribution) AS DECIMAL)/CAST(SUM(T2.maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS AllAvg , 
      MAX(T2.MeridianScore) AS AllUpperScore , 
      MIN(T2.MeridianScore) AS AllLowerScore 
    FROM (SELECT PHR.PKID , 
         ShortName , 
         CAST((CAST(SUM(contribution) AS DECIMAL)/CAST(SUM(maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS MeridianScore , 
         SUM(Contribution) AS Contribution , 
         SUM(MaxValue) AS MaxValue 
       FROM  @PreHierarchyResults AS PHR 
         INNER JOIN TVF_GetChildGroups(@AreaID) AS TGCG ON TGCG.GroupName = PHR.Branch 
       GROUP BY PHR.PKID , ShortName) AS T1 
      RIGHT JOIN (SELECT PHR2.PKID , 
           ShortName , 
           CAST((CAST(SUM(Contribution) AS DECIMAL)/CAST(SUM(Maxvalue) AS DECIMAL) * 100) AS DECIMAL(5, 2)) AS MeridianScore , 
           SUM(Contribution) AS Contribution , 
           SUM(MaxValue) AS MaxValue 
         FROM @PreHierarchyResults AS PHR2 
           INNER JOIN TVF_GetChildGroups(@RootReportLevelID) AS TGCG ON TGCG.GroupName = PHR2.Branch 
         GROUP BY PHR2.PKID , ShortName) AS T2 ON T1.ShortName = T2.ShortName 
    GROUP BY T2.ShortName 

对于原来的SQL我得到执行时间:

SQL Server的执行时间:
CPU时间= 16毫秒,经过的时间= 11毫秒。
表'#012F94F2'。扫描计数0,逻辑读取3,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读数0.
表'tblUploadedScoreCardResults'。扫描计数4456,逻辑读取13943,物理读取40,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读数0. 表'工作表'。扫描计数6,逻辑读取29800,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUserGroups'。扫描计数2,逻辑读取118,物理读取1,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUploadedScorecards'。扫描计数0,逻辑读取29496,物理读取8,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUploadedScorecardHeaders'。扫描计数192,逻辑读取746,物理读取5,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'#7D5F040E'。扫描计数186,逻辑读取372,物理读取0次,预读0,lob逻辑读取0,lob物理读取0次,lob预读0

和重构后我得到:

SQL Server执行时间:
CPU时间= 0毫秒,经过时间= 10毫秒。
表'#48563EF2'。扫描计数0,逻辑读取5106,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0.
表'tblUploadedScoreCardResults'。扫描计数185,逻辑读取614,物理读取41,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUploadedScorecards'。扫描计数0,逻辑读取370,物理读取8,预读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUploadedScorecardHeaders'。扫描计数7,逻辑读取23,物理读取5,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'#439189D5'。扫描计数1,逻辑读取2,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
(5059行受影响)
(1 row (s)affected)

SQL Server执行时间:
CPU时间= 16毫秒,经过时间= 199毫秒。
表'#47621AB9'。扫描计数0,逻辑读取3,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0.
表'工作台'。扫描计数114,逻辑读取1770,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'tblUserGroups'。扫描计数112,逻辑读取998,物理读取1,预读读取0,lob逻辑读取0,lob物理读取0,lob预读取读取0.
表'#48563EF2'。扫描计数112,逻辑读取5376次,物理读取0,预读0,lob逻辑读取0,lob物理读取0次,lob预读0

望着输出我觉得很明显,第一个版本更高效,但我不明白为什么它应该是这种情况,因为它似乎两次触发4个表格,而在第二个版本中这些表格只触发一次。

回答

0

我还会比较原始查询和修订查询之间的实际执行计划。

另请检查tblUploadedScorecards,tblUploadedScoreCardResults和上的索引。将这些表中的数据缓存到@PreHierarchyResults后,您可能会失去第二个查询中连接列上某些覆盖索引的好处。

相关问题