Estou revisando um procedimento armazenado que tem sido um problema de desempenho. E acabei de perceber que algumas das tabelas que são usadas no procedimento armazenado nem aparecem nos resultados do Set Statistics I/O?
Isso é normal ou é um bug? É um pouco perturbador porque eu uso muito os resultados do Set Statistics I/O, ao descobrir o que indexar.
As tabelas que não aparecem na saída de Set Statistics I/O estão em uma subseleção na consulta principal, como a tabela ActivityFeedCache abaixo:
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
Este é o SQL Server 2017 (RTM-CU13).
EDIT: Eu reduzi a uma pequena consulta que mostra uma tabela ausente na saída de E/S de Estatísticas. A tabela Locales está ausente em Statistics I/O, mas aparece no plano de execução. Aqui está:
-- 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)
Aqui está a saída de Estatísticas de E/S:
(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.
E aqui está um pequeno pedaço do XML do plano de execução real, apenas para que você possa ver que a tabela Locales está realmente sendo usada:
<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]">
Há um cenário em que um plano de execução estimado pode conter um operador que não é usado em tempo de execução, por exemplo, quando um predicado torna o operador não operacional.
É difícil identificar porque não há muitas pistas do que aconteceu, exceto que o operador
actual execution count
é 0. Ajudei a conduzir uma mudança no SentryOne Plan Explorer que o torna mais óbvio - o ícone do operador fica esmaecido. Você pode ler sobre essa alteração nesta postagem do blog sob o título "Aplicar opacidade para operadores com 0 execuções + linhas reais".Se uma tabela for tocada apenas por um único operador no plano de execução e esse operador for eliminado em tempo de execução (o que significa que a tabela não é tocada), essa tabela não aparecerá no
Statistics IO
.