我正在尝试优化存储过程,在查看执行计划和执行时间后,我对结果感到惊讶。谁能解释一下。
我编写的原始 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 个表,而在第二个版本中,这些表只被击中一次.