Benjamin Nevarez é um consultor independente com sede em Los Angeles, Califórnia, especializado em ajuste e otimização de consultas do SQL Server. Ele é o autor de “SQL Server 2014 Query Tuning &Optimization” e “Inside the SQL Server Query Optimizer” e coautor de “SQL Server 2012 Internals”. Com mais de 20 anos de experiência em bancos de dados relacionais, Benjamin também foi palestrante em muitas conferências do SQL Server, incluindo o PASS Summit, SQL Server Connections e SQLBits. O blog de Benjamin pode ser encontrado em http://www.benjaminnevarez.com e ele também pode ser contatado por e-mail em admin em benjaminnevarez ponto com e no twitter em @BenjaminNevarez.
Um grande problema com a atualização de estatísticas em tabelas grandes no SQL Server é que a tabela inteira sempre precisa ser verificada, por exemplo, ao usar o
WITH FULLSCAN
opção, mesmo que apenas os dados recentes tenham sido alterados. Isso também é verdade ao usar o particionamento:mesmo que apenas a partição mais recente tenha sido alterada desde a última vez que as estatísticas foram atualizadas, atualizar as estatísticas novamente é necessário para verificar a tabela inteira, incluindo todas as partições que não foram alteradas. Estatísticas incrementais, um novo recurso do SQL Server 2014, podem ajudar com esse problema. Usando estatísticas incrementais, você pode atualizar apenas a partição ou partições necessárias e as informações dessas partições serão mescladas com as informações existentes para criar o objeto de estatísticas final. Outra vantagem das estatísticas incrementais é que a porcentagem de alterações de dados necessárias para acionar uma atualização automática de estatísticas agora funciona no nível da partição, o que basicamente significa que agora apenas 20% das linhas alteradas (alterações na coluna de estatísticas principal) por partição são necessárias. Infelizmente, o histograma ainda está limitado a 200 etapas para todo o objeto de estatísticas nesta versão do SQL Server.
Vejamos um exemplo de como você pode atualizar estatísticas em um nível de partição para explorar seu comportamento pelo menos a partir do SQL Server 2014 CTP2. Primeiro precisamos criar uma tabela particionada usando o banco de dados AdventureWorks2012:
CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME) AS RANGE RIGHT FOR VALUES ( '20071001', '20071101', '20071201', '20080101', '20080201', '20080301', '20080401', '20080501', '20080601', '20080701', '20080801' ); GO CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO ( [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY] ); GO CREATE TABLE dbo.TransactionHistory ( TransactionID INT NOT NULL, -- not bothering with IDENTITY here ProductID INT NOT NULL, ReferenceOrderID INT NOT NULL, ReferenceOrderLineID INT NOT NULL DEFAULT (0), TransactionDate DATETIME NOT NULL DEFAULT (GETDATE()), TransactionType NCHAR(1) NOT NULL, Quantity INT NOT NULL, ActualCost MONEY NOT NULL, ModifiedDate DATETIME NOT NULL DEFAULT (GETDATE()), CONSTRAINT CK_TransactionType CHECK (UPPER(TransactionType) IN (N'W', N'S', N'P')) ) ON TransactionsPS1 (TransactionDate); GO
Observação:para obter detalhes sobre particionamento e
CREATE PARTITION FUNCTION / SCHEME
instruções, consulte Tabelas e Índices Particionados nos Manuais Online. Atualmente temos dados para preencher 12 partições. Vamos começar primeiro preenchendo apenas 11.
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate < '2008-08-01';
Se necessário, você pode usar a seguinte instrução para inspecionar o conteúdo das partições:
SELECT * FROM sys.partitions WHERE object_id = OBJECT_ID('dbo.TransactionHistory');
Vamos criar um objeto de estatísticas incrementais usando o
CREATE STATISTICS
instrução com o novo INCREMENTAL
cláusula definida como ON
(OFF
é o padrão):CREATE STATISTICS incrstats ON dbo.TransactionHistory(TransactionDate) WITH FULLSCAN, INCREMENTAL = ON;
Você também pode criar estatísticas incrementais ao criar um índice usando o novo
STATISTICS_INCREMENTAL
cláusula do CREATE INDEX
demonstração. Você pode inspecionar o objeto de estatísticas criado usando
DBCC
:DBCC SHOW_STATISTICS('dbo.TransactionHistory', incrstats);
Entre outras coisas, você notará que o histograma tem 200 passos (apenas os 3 últimos mostrados aqui):
RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
198 | 2008-07-25 00:00:00.000 | 187 | 100 | 2 |
199 | 2008-07-27 00:00:00.000 | 103 | 101 | 1 |
200 | 2008-07-31 00:00:00.000 | 281 | 131 | 3 |
Resultados iniciais do DBCC
Então já temos o máximo de passos em um objeto de estatística. O que aconteceria se você adicionasse dados a uma nova partição? Vamos adicionar dados à partição 12:
INSERT INTO dbo.TransactionHistory SELECT * FROM Production.TransactionHistory WHERE TransactionDate >= '2008-08-01';
Agora, atualizamos o objeto de estatísticas usando a seguinte instrução:
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH RESAMPLE ON PARTITIONS(12);
Observe a nova sintaxe que especifica a partição, onde você pode especificar várias partições, separadas por vírgula. O
UPDATE STATISTICS
A instrução lê as partições especificadas e, em seguida, mescla seus resultados com o objeto de estatística existente para criar as estatísticas globais. Observe o RESAMPLE
cláusula; isso é necessário, pois as estatísticas de partição precisam ter as mesmas taxas de amostragem a serem mescladas para criar as estatísticas globais. Embora apenas a partição especificada tenha sido verificada, você pode ver que o SQL Server reorganizou o histograma. As últimas três etapas agora mostram dados para a partição adicionada. Você também pode comparar o original com o novo histograma para outras pequenas diferenças:RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | |
197 | 2008-07-31 00:00:00.000 | 150 | 131 | 2 |
198 | 2008-08-12 00:00:00.000 | 300 | 36 | 9 |
199 | 2008-08-22 00:00:00.000 | 229 | 43 | 7 |
200 | 2008-09-03 00:00:00.000 | 363 | 37 | 11 |
Resultados do DBCC após a atualização incremental
Se por algum motivo você quiser desabilitar as estatísticas incrementais, você pode usar a seguinte instrução para voltar ao comportamento original (ou, opcionalmente, apenas descartar o objeto de estatísticas e criar um novo).
UPDATE STATISTICS dbo.TransactionHistory(incrstats) WITH FULLSCAN, INCREMENTAL = OFF;
Após desabilitar as estatísticas incrementais, tentar atualizar uma partição conforme mostrado anteriormente retornará a seguinte mensagem de erro:
Msg 9111, Level 16, State 1
UPDATE STATISTICS ON PARTITIONS sintaxe não é suportada para estatísticas não incrementais.
Por fim, você também pode habilitar estatísticas incrementais para suas estatísticas automáticas no nível do banco de dados, se necessário. Isso requer o
INCREMENTAL = ON
cláusula no ALTER DATABASE
e obviamente também requer AUTO_CREATE_STATISTICS
definido como ON
.