Problema-chave crescente - coluna principal com a marca “Estacionário” - SQL Server

9

Pesquisei consultas de execução lenta em nosso banco de dados e concluímos que esse é um problema-chave crescente crescente. À medida que novas linhas são inseridas quase constantemente, e uma determinada parte do SQL para extrair os dados mais recentes do DB é executada a cada 30 minutos, a primeira opção de atualização de estatísticas a cada 30 minutos parecia um desperdício de recursos.

Portanto, examinei o Trace Flag 2389, que em princípio deve ajudar, no entanto, isso exige que a coluna Leading seja identificada como Ascendente, e quando usei o Trace Flag 2388 para verificar as estatísticas do índice (PK), vejo que a coluna principal é realmente marcado como estacionário - como é para vários índices de PK em outras tabelas atualizadas ao mesmo tempo.

insira a descrição da imagem aqui

Não parece haver muita orientação sobre o que resulta em uma marca de estacionário, no entanto, encontrei o KB2952101 que diz que se menos de 90% das inserções fossem maiores que o valor máximo antigo, ele seria classificado como estacionário. Todas as nossas inserções são novos envios, e a coluna principal é uma coluna bigint IDENTITY, portanto, 100% das inserções devem ser maiores que o valor máximo anterior.

Então, minha pergunta é por que a coluna seria marcada como estacionária, quando obviamente está em ascensão?

Uma tentativa anterior de resolver esse problema para algum SQL em execução diário (que funcionou muito bem) resultou na instalação de um trabalho para atualizar as estatísticas desta tabela todas as noites. A atualização não faz um FULLSCAN; pode ser que a varredura amostrada esteja perdendo as novas linhas algumas vezes, portanto nem sempre é exibida como ascendente?

A única outra coisa que consigo pensar que pode afetar isso é que temos um trabalho de arquivamento sendo executado nos bastidores, excluindo linhas acima de uma certa idade. Isso pode afetar a marca?

O servidor é o SQL Server 2012 SP1.

Atualização : outro dia, outra atualização de estatísticas - a mesma marca estacionária. Houve 28049 novas inserções desde a atualização anterior das estatísticas. Cada linha tem um registro de data e hora de quando foi inserida; portanto, se eu selecionar max (id) da tabela em que o registro de data e hora <'20161102' recebo 23313455 Da mesma forma, se fizer isso para quando as estatísticas forem atualizadas hoje, recebo 23341504.

A diferença entre essas e as 28049 novas inserções; portanto, como você pode ver, todas as novas inserções receberam novas chaves ascendentes (conforme o esperado), sugerindo que a coluna principal deve ser identificada como ascendente e não estacionária.

Durante o mesmo período, nosso trabalho de arquivamento excluiu 213.629 linhas (estamos limpando lentamente os dados antigos). Existe alguma chance de que um número de linhas reduzido possa contribuir para a marca estacionária? Eu testei isso antes e não parecia fazer nenhuma diferença.

Atualização 2 : outro dia, outra atualização de estatísticas e a coluna agora está sinalizada como Ascendente! De acordo com a teoria sobre exclusões que afetam isso, verifiquei a porcentagem de atualizações sendo inserções em comparação com exclusões, e ontem 13% eram inserções, enquanto que as inserções nos dois dias anteriores representavam cerca de 12%. Eu não acho que isso nos dê algo conclusivo.

Curiosamente, uma tabela relacionada que obtém, em média, 4 linhas inseridas para cada linha inserida nessa tabela principal, e que possui estatísticas atualizadas ao mesmo tempo, tem a coluna IDENTITY PK ainda como estacionária !?

Atualização 3 : no fim de semana, recebemos mais inserções. Esta manhã, a coluna principal está de volta a Estacionária. Na última atualização de estatísticas, tivemos 46840 inserções e apenas 34776 exclusões.

Mais uma vez, curiosamente, a tabela relacionada que mencionei acima agora tem sua coluna principal com a marca Ascendente. Não existe documentação que possa explicar isso?

Atualização 4 : já faz uma semana ou mais, o trabalho de arquivamento limpou a lista de pendências; portanto, estamos excluindo consistentemente cerca de dois terços do número de linhas inseridas. As estatísticas estão mostrando resultados mistos nas tabelas relacionadas, com um parado e dois mostrando ascendente, apesar de todos terem sido atualizados proporcionalmente da mesma forma.

Nik
fonte
No nosso caso, todas as inserções têm valores que estão além do valor mais alto no histograma; portanto, a coluna não deve ter a marca estacionária, por isso não tentei o sinalizador. É uma explicação de por que o SQL Server parece marcar aleatoriamente as colunas que realmente busco. Obrigado.
Nik

Respostas:

3

Parece não haver muita orientação sobre o que resulta em uma marca de estacionário, no entanto, encontrei o KB2952101 que diz que se menos de 90% das inserções fossem maiores que o valor máximo antigo, ele seria classificado como estacionário. Todas as nossas inserções são novas submissões, e a coluna principal é uma coluna bigint IDENTITY; portanto, 100% das inserções devem ser maiores que o valor máximo anterior.

Então, minha pergunta é por que a coluna seria marcada como estacionária, quando obviamente está em ascensão?

Será marcado como estacionário se, como você já indicou, 10% ou mais das inserções não estiverem subindo. Se 100% de suas inserções fossem como você diz ... então você pode não ter esse problema, até que você exclua, é claro, mas isso voltará a desconhecido.

Aqui está uma reprodução do seu problema:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go
Sean Gallardy - Usuário aposentado
fonte
Fiz um teste rápido usando o mesmo script acima, mas apenas executei a inserção e a exclusão de partes. Parece que, se você excluir uma quantidade muito maior de linhas do que a inserida, ela voltará a estacionária (novamente cerca de 10%). Nos seus dados atualizados, você inseriu aproximadamente 10% de todas as alterações feitas nos dados - parece que as exclusões estão causando sofrimento. Nesse ponto, eu sugeriria deixar o objeto stats bater em ascendente e congelá-lo, não atualizando-o.
Sean Gallardy - Usuário aposentado
Tentei recriar o que você tinha feito e acabei adicionando mais 10 linhas e excluindo 1000, atualizando estatísticas e mostrando estatísticas, e ainda aparece como ascendente: Inserções desde a última atualização: 10, Exclusões desde a última atualização: 1000, Tipo de coluna principal : Crescente. Não sabe por que recebo um resultado diferente para você? Se suas descobertas estiverem corretas, pode ser apenas um caso de resultados menos que ótimos agora, e quando nosso backlog de arquivamento terminar, tente novamente.
Nik
0

Na minha opinião, a menos que você esteja gerando a coluna-chave principal no próprio servidor, poderá entrar em pequenos buracos contando com a geração de clientes individuais.

Além disso, você já tentou o Trace Flag 2371.

O TF 2371 está documentado aqui .

O KB é intitulado "Controlando o comportamento do Autostat (AUTO_UPDATE_STATISTICS) no SQL Server". e o KB é 2754171.

Será muito útil se você listar para nós os impactos reais dos novos dados que não estão nas estatísticas a tempo.

Foram escolhidos índices errados. E, se sim, você pode listar para nós os índices e suas chaves primárias?

Além disso, você pode compartilhar os planos gerados quando as estatísticas são datadas quando são oportunas. Eu gostaria de comparar os dois.

Meu pensamento é que as decisões do SQL Cost Based Optimizer (Rules and Costing) são muito boas; fora de áreas esotéricas como esta.

Se esse for um caso especial, mais explicações podem ser úteis e justificar a abertura de um Item de Conexão.

Como um aparte, na minha humilde opinião, você terá maiores benefícios gerais ao fazer com que o fornecedor use SP que o SQL ad-hoc.

Daniel Adeniji
fonte
Obrigado, os IDs são todos criados pelo SQL Server. Entendo que o sinalizador 2371 apenas torna as atualizações de estatísticas mais frequentes. A julgar pela tabela em brentozar.com/archive/2016/03/… , o tamanho da nossa tabela (14 milhões de linhas) e o número de inserções diárias (28 mil linhas), as estatísticas ainda são atualizadas apenas a cada 4 dias, portanto, a extração de novos dados, na maioria das vezes, não os conhece. As consultas que olhei não são uma preocupação, é entender como o SQL Server marca a coluna principal que eu gostaria de conhecer. Obrigado novamente.
Nik