ストアド プロシージャを最適化しようとしていますが、実行計画と実行時間を調べたところ、結果に驚きました。誰でも説明できますか。
私が書いた元の 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 回ヒットするように見えるため、なぜそうなるのか理解できません。 .