我正在审查一个存在性能问题的存储过程。而且我刚刚意识到存储过程中使用的一些表甚至根本没有出现在 Set Statistics I/O 的结果中?
这是正常现象还是bug?这有点令人不安,因为在确定要索引的内容时,我经常使用 Set Statistics I/O 的结果。
未显示在 Set Statistics I/O 输出中的表位于主查询的子选择中,例如下面的 ActivityFeedCache 表:
SELECT *
FROM (
SELECT AF.ActivityFeedID
,A.ActivityType AS ActivityType
,A.IconClass
,AF.SubscriptionID
,AF.ObjectID
,AF.ObjectType
,(
SELECT L.Locale
,AFC.LocalizedMessage
FROM ActivityFeedCache AFC
JOIN Locales L
ON AFC.LocaleID = L.LocaleID
WHERE ActivityFeedID = AF.ActivityFeedID
FOR JSON PATH
) AS MessageJSON
FROM ActivityFeed AF
ETC
ETC
) AS Results
这是 SQL Server 2017 (RTM-CU13)。
编辑:我已经缩小到一个小查询,显示统计 IO 输出中缺少一个表。统计 I/O 中缺少 Locales 表,但显示在执行计划中。这里是:
-- Locales table doesn't show in statistics i/o output
SELECT AF.ActivityFeedID
,(
SELECT L.Locale
,AFC.LocalizedTeamMessage AS LocalizedMessage
FROM ActivityFeedTeamCache AFC
JOIN Locales L
ON AFC.LocaleID = L.LocaleID
WHERE ActivityFeedID = AF.ActivityFeedID
FOR JSON PATH
) AS TeamMessageJSON
FROM ActivityFeed AF
Where AF.ActivityFeedID = (select top 1 ActivityFeedID from ActivityFeed)
这是统计 I/O 输出:
(1 row affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ActivityFeedTeamCache'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'ActivityFeed'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
下面是实际执行计划 XML 的一小部分,以便您可以看到实际使用了 Locales 表:
<IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
<DefinedValues>
<DefinedValue>
<ColumnReference Database="[Database1]" Schema="[dbo]" Table="[Locales]" Alias="[L]" Column="Locale" />
</DefinedValue>
</DefinedValues>
<Object Database="[Database1]" Schema="[dbo]" Table="[Locales]" Index="[PK_Locales]" Alias="[L]" IndexKind="Clustered" Storage="RowStore" />
<SeekPredicates>
<SeekPredicateNew>
<SeekKeys>
<Prefix ScanType="EQ">
<RangeColumns>
<ColumnReference Database="[Database1]" Schema="[dbo]" Table="[Locales]" Alias="[L]" Column="LocaleID" />
</RangeColumns>
<RangeExpressions>
<ScalarOperator ScalarString="[Database1].[dbo].[ActivityFeedTeamCache].[LocaleID] as [AFC].[LocaleID]">
在某些情况下,估计的执行计划可能包含一个在运行时不使用的运算符,例如,当谓词使该运算符成为无操作时。
很难发现它,因为它发生的线索不多,除了操作员的
actual execution count
为 0。我帮助推动了 SentryOne Plan Explorer 的更改,使其更加明显 - 操作员图标变暗。您可以在这篇博客文章的标题下阅读有关此更改的信息,“对执行次数为 0 + 实际行的运算符应用不透明度”。如果一个表只被执行计划中的单个运算符触及,并且该运算符在运行时被消除(意味着该表没有被触及),则该表将不会出现在
Statistics IO
.