Venho investigando os limites de amostragem com atualizações de estatísticas no SQL Server (2012) e notei algum comportamento curioso. Basicamente, o número de linhas amostradas parece variar em algumas circunstâncias - mesmo com o mesmo conjunto de dados.
Eu executo esta consulta:
--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;
--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);
--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue)
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;
--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);
--Update Statistics without specifying how many rows to sample
UPDATE STATISTICS dbo.Test IX_Test_TextValue;
--View the Statistics
DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER;
Quando olho para a saída do SHOW_STATISTICS, percebo que as "Linhas amostradas" variam a cada execução completa (ou seja, a tabela é descartada, recriada e repovoada).
Por exemplo:
Linhas amostradas
- 318618
- 319240
- 324198
- 314154
Minha expectativa era que esse número fosse o mesmo sempre que a tabela for idêntica. A propósito, eu não entendo esse comportamento se apenas excluir os dados e inseri-los novamente.
Não é uma pergunta crítica, mas eu estaria interessado em entender o que está acontecendo.
fonte
318618 = 1142*279
,319240 = 1144*279 + 64
,324198=1162*279
E314154=1126
por isso a variância é o número de páginas amostrados.Respostas:
fundo
Os dados para o objeto de estatísticas são coletados usando uma declaração do formulário:
Você pode coletar esta declaração com Eventos Estendidos ou Profiler (
SP:StmtCompleted
).As consultas de geração de estatísticas geralmente acessam a tabela base (em vez de um índice não clusterizado) para evitar o agrupamento de valores que ocorre naturalmente em páginas de índice não clusterizadas.
O número de linhas amostradas depende do número de páginas inteiras selecionadas para amostragem. Cada página da tabela está selecionada ou não. Todas as linhas nas páginas selecionadas contribuem para as estatísticas.
Números aleatórios
O SQL Server usa um gerador de números aleatórios para decidir se uma página é qualificada ou não. O gerador usado nesta instância é o gerador de números aleatórios Lehmer com valores de parâmetros, como mostrado abaixo:
O valor de é calculado como a soma de:
Xseed
A parte inteira baixa da
bigint
tabela base ( ),partition_id
por exemplo,O valor especificado na
REPEATABLE
cláusulaUPDATE STATISTICS
, oREPEATABLE
valor é 1.m_randomSeed
elemento das informações de depuração internas do método de acesso mostradas nos planos de execução quando o sinalizador de rastreamento 8666 está ativado, por exemplo<Field FieldName="m_randomSeed" FieldValue="1" />
Para o SQL Server 2012, esse cálculo ocorre em
sqlmin!UnOrderPageScanner::StartScan
:onde a memória em
[rcx+30h]
contém os 32 bits baixos do ID da partição e a memória em[rcx+2Ch]
contém oREPEATABLE
valor em uso.O gerador de números aleatórios é inicializado posteriormente no mesmo método, chamando
sqlmin!RandomNumGenerator::Init
, onde a instrução:... multiplica a semente por
41A7
hexadecimal (16807 decimal = 7 5 ), como mostrado na equação acima.Números aleatórios posteriores (para páginas individuais) são gerados usando o mesmo código básico incorporado
sqlmin!UnOrderPageScanner::SetupSubScanner
.StatMan
Para a
StatMan
consulta de exemplo mostrada acima, as mesmas páginas serão coletadas como para a instrução T-SQL:Isso corresponderá à saída de:
Caso borda
Uma conseqüência do uso do gerador de números aleatórios MINSTD Lehmer é que os valores de zero e int.max não devem ser usados, pois isso resultará no algoritmo produzindo uma sequência de zeros (selecionando todas as páginas).
O código detecta zero e usa um valor do 'relógio' do sistema como a semente nesse caso. Não faz o mesmo se a semente estiver int.max (
0x7FFFFFFF
= 2 31 - 1).Podemos projetar esse cenário, pois a semente inicial é calculada como a soma dos 32 bits baixos do ID da partição e do
REPEATABLE
valor. OREPEATABLE
valor que resultará na semente sendo int.max e, portanto, todas as páginas selecionadas para amostra são:Trabalhando isso em um exemplo completo:
Isso selecionará todas as linhas de todas as páginas, independentemente da
TABLESAMPLE
cláusula (mesmo zero por cento).fonte
Esta é uma excelente pergunta! Vou começar com o que tenho certeza e depois passar para a especulação. Muitos detalhes sobre isso no meu post aqui .
As atualizações de estatísticas amostradas são usadas
TABLESAMPLE
nos bastidores. É muito fácil encontrar documentação sobre isso online. No entanto, acredito que não é bem sabido que as linhas retornadas porTABLESAMPLE
dependem parcialmentehobt_id
da do objeto. Quando você solta e recria o objeto, obtém um novohobt_id
para que as linhas retornadas por amostragem aleatória sejam diferentes.Se você excluir e reinserir os dados,
hobt_id
os mesmos permanecerão. Desde que os dados sejam dispostos da mesma maneira no disco (uma varredura de ordem de alocação retorna os mesmos resultados na mesma ordem), os dados amostrados não devem ser alterados.Você também pode alterar o número de linhas amostradas recriando o índice em cluster na tabela. Por exemplo:
Por que isso acontece, acredito que é porque o SQL Server verifica o índice em cluster em vez do índice não clusterizado ao reunir estatísticas de amostra em um índice. Também acho que há um valor oculto (para aqueles que rastreiam as consultas de atualização de estatísticas ocultas) para serem
REPEATABLE
usadosTABLESAMPLE
. Não provei nada disso, mas explica por que o histograma e as linhas amostradas são alteradas com uma reconstrução do índice clusterizado.fonte
Vi isso no Inside Microsoft SQL Server 2008: Consulta T-SQL por Itzik Ben-Gan e não posso adicioná-lo como um comentário, por isso, posto aqui, acho interessante também para outros:
Veja também Amostragem usando TABLESAMPLE da Roji. P. Thomas.
fonte