1

ストアド プロシージャを最適化しようとしていますが、実行計画と実行時間を調べたところ、結果に驚きました。誰でも説明できますか。

私が書いた元の SQL には 2つのほぼ同一の選択があり、それを CTE にまとめました。リファクタリングを試みたので、主な作業は一度完了し、テーブル変数にデータを入力して、データをフィルター処理する 2 つの小さな選択を行うことができました。必要だった。2 つの select ステートメントの唯一の違いは、1 番目の select @AreaID で TVF_GetChildGroups に渡される値が現在のコンテキストのレポート領域を表し、2 番目の 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。
テーブル 'Worktable'。スキャン カウント 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。

出力を見ると、最初のバージョンの方が効率的であることは明らかだと思いますが、2 番目のバージョンではこれらのテーブルが 1 回しかヒットしないのに対し、4 つのテーブルに 2 回ヒットするように見えるため、なぜそうなるのか理解できません。 .

4

1 に答える 1

0

また、元のクエリと修正したクエリの実際の実行計画を比較します。

tblUploadedScorecardstblUploadedScoreCardResults、およびのインデックスも確認してくださいtblUploadedScorecardHeaders。これらのテーブルのデータを @PreHierarchyResults にキャッシュした後、2 番目のクエリの結合列のインデックスをカバーする利点が失われる可能性があります。

于 2012-07-06T18:02:15.023 に答える