Para um exemplo de tabela rowstore...
CREATE TABLE T(Id INT PRIMARY KEY, C1 INT NULL, C2 INT NULL);
Existem vários métodos diferentes para recuperar contagens de linhas de tabela de metadados no SQL Server - como o abaixo
SELECT SUM(rows)
FROM sys.partitions
WHERE object_id = object_id('dbo.T') AND index_id <= 1;
SELECT SUM(row_count)
FROM sys.dm_db_partition_stats
WHERE object_id = object_id('dbo.T') AND index_id <= 1;
SELECT SUM(rows)
FROM sys.sysindexes
WHERE id = object_id('dbo.T') AND indid <= 1;
SELECT OBJECTPROPERTYEX(object_id('dbo.T'), 'Cardinality')
Os planos de execução aparentemente mostram uma variedade de objetos diferentes sendo usados - como o abaixo.
- sysrowsets OUTER APPLY OpenRowset(TABLE ALUCOUNT
- sysidxstats CROSS APPLY OpenRowSet(TABELA PARTITIONCOUNTS
- sysidxstats i CROSS APPLY OpenRowSet(TABLE INDEXPROP
O que está acontecendo aqui? O SQL Server realmente mantém esses metadados em vários lugares? Se sim, qual é o método mais confiável?
Para analisar isso, criei um novo banco de dados conforme abaixo
Isso criou um banco de dados com um único arquivo de dados e usei o Process Monitor para monitorar as operações de WriteFile nele. E então executei
O ProcMon mostrou as seguintes páginas gravadas no disco
Tirando os deslocamentos disso para ver a quais objetos eles pertencem
Devolvido
sysallocunits
Possui colunas relevantes para contagens de páginas, mas nada sobre contagem de linhas,sysrscols
contém as contagens de modificações por coluna usadas para recompilações do plano de execução baseado em cardinalidade, mas, novamente, nenhuma coluna de contagem de linhas. A única dessas tabelas base do sistema que possui uma coluna de contagem de linhas estárcrows
emsysrowsets
.Então concluo que todos esses métodos, em última análise, obtêm o valor do mesmo lugar, pois ele é armazenado persistentemente em apenas um lugar.
Eu também executei o abaixo
A parte relevante do log de transações após o primeiro manual
CHECKPOINT
está abaixoAs várias
LOP_COUNT_DELTA
entradas mostram alguns aspectos interessantesLOP_COMMIT_XACT
transações do usuário (ou seja, não fazem parte dessas transações)LOP_COUNT_DELTA
configuração de entradaRow count: 104
)Então, se a contagem de linhas em sysrowsets for atualizada apenas periodicamente, isso significa que os valores de metadados retornados estão incorretos?
Todos os métodos fornecidos na pergunta ainda retornavam a contagem correta de linhas antes de serem gravadas
sysrowsets
. Presumo que a contagem seja atualizada para as estruturas de memória usadas pelos vários DMFs internos (ALUCOUNT
/PARTITIONCOUNTS
/INDEXPROP
).Eu até mesmo matei o processo do SQL Server antes que as alterações
sysrowsets
fossem gravadas no disco e eles ainda retornaram os valores corretos após a reinicialização do serviço, então presumo que os deltas não verificados sejam recalculados como parte da recuperação do banco de dados.A contagem de linhas é documentada como algo que pode dar errado e precisar de correção, mas não tenho certeza de quais são as circunstâncias que podem causar isso.
Todos os métodos listados na pergunta recuperam a contagem de linhas por meio de uma chamada para
sqlmin!GrabRowsetCounts
:sys.partitions
sys.dm_db_partition_stats
sys.sysindexes
OBJECTPROPERTYEX
Como você observou, as informações são salvas apenas em uma tabela interna.
Como rotina, as contagens de conjuntos de linhas são mantidas na memória para cada HoBt. Para operações por linha, isso significa literalmente que um contador é incrementado ou decrementado para cada modificação de linha, por exemplo, por meio de uma chamada para
sqlmin!BaseSharedHoBt::DeltaRowCount
.LOP_COUNT_DELTA
Os registros de log para alterações líquidas são gravados em pontos de verificação por meio desqlmin!FlushHoBtsDeltaCounts
:Observe que muitos dos nomes de métodos indicam que eles não são transacionais.