1

我正在尝试优化存储过程,在查看执行计划和执行时间后,我对结果感到惊讶。谁能解释一下。

我编写的原始 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 行)

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 个表,而在第二个版本中,这些表只被击中一次.

4

1 回答 1

0

我还将比较您的原始查询和修改后的查询之间的实际执行计划。

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

于 2012-07-06T18:02:15.023 回答