Quando Ghost Records viram um problema de performance no SQL Server!

Quando Ghost Records viram um problema de performance no SQL Server!

Recentemente analisamos um caso em produção muito interessante. Um job que executava em cerca de 5 minutos, passou a ficar cada dia mais lento até chegar a 48 minutos.

Sem alterações na rotina ou no ambiente que justificassem essa demora. Tentamos simular em base de HML e não estava sendo possível reproduzir o cenário. Sem waits que justificassem, tempo de processamento era +90% CPU, sem spinlocks com impactos diretos, fizemos diversos testes para entender a diferença em uma base cópia.

O processo era “complexo”. Muitos loops de DELETES faziam com que o plano de execução não fosse gerado inteiro para conseguirmos comparar efetivamente.


Primeiros testes

Então decidimos simplificar as comparações entre os ambientes, e testamos um simples SELECT TOP (5000) na tabela que mais apresentava lentidão no processo.

Comparando os ambientes produtivo e HML teve uma grande diferença:

  • ~2700ms em produção

  • 16ms em HML

(tempo de CPU)

Ambientes visualmente iguais, hardware equivalente, configurações similares, plano de execução com os mesmos operadores e estimativas, estatísticas iguais… nada parecia diferente para justificar.


Um comportamento curioso

Após restaurar a base novamente para novos testes tivemos uma boa surpresa: a query demorou nas 3 primeiras execuções e depois voltou a ficar com 16ms nas demais.

Apenas na primeira execução teve leituras físicas / read-ahead, então não seria uma justificativa para as execuções subsequentes também terem tempo de CPU alto.

Repetimos esse teste para pegar mais informações e reparamos que a quantidade de leituras lógicas começava alta e caía aos poucos.


O efeito do rebuild

Vimos que, com o REBUILD do índice cluster após o restore, a consulta não apresentava mais lentidão nas primeiras execuções. Já iniciava com o tempo esperado de 16ms.

A fragmentação do índice também não justificava os sintomas.

Aí começou uma nova busca para entender o que o rebuild resolve, impacta nas leituras lógicas e não é fragmentação.

Parece até uma charada rsrs.


A hipótese que explicou tudo

Conversando internamente com o time para ajudarem com ideias, a Raiane Flores Borba Lins deu várias ideias e hipóteses.

Mas todas já haviam sido testadas e descartadas, menos a última:

“Ghost Records”

Algo que ainda não havia sido validado.

Causaria os mesmos sintomas e seria resolvido com o rebuild.


Validação do cenário

Para conseguirmos comprovar, desativamos o processo do Ghost Cleanup em uma nova instância para testes.

Subimos a base e conseguimos validar que a tabela tinha mais de 11 milhões de ghost records.

Algumas tabelas na base passavam de 40 milhões.


O que são Ghost Records

No SQL Server, quando um registro é deletado, ele nem sempre é removido fisicamente naquele momento.

Muitas vezes ele é apenas marcado para remoção futura, ficando como “ghost record”.

A limpeza física é feita periodicamente por um processo interno chamado Ghost Cleanup.


O impacto na prática

Na prática, isso fazia uma consulta simples como:

SELECT TOP (5000)

precisar percorrer dezenas de milhares de páginas para encontrar 5.000 linhas válidas.

O resultado foi:

  • alto volume de leituras lógicas

  • aumento de CPU

À medida que o Ghost Cleanup avançava, a mesma consulta passava a executar com poucas leituras e CPU praticamente zero.

O mesmo efeito também foi validado com rebuild de índice, que reduziu drasticamente a quantidade de ghost records e devolveu a performance esperada.


Por que o problema não apareceu antes

Uma característica do Ghost Cleanup é que, após um scan na tabela ou índice, as ghost records são enfileiradas para que ele possa fazer a limpeza.

Isso fez com que os testes iniciais em HML resolvessem o problema antes de conseguirmos identificar a causa, nos levando para outros caminhos.

O cuidado do cliente em não permitir scans na tabela fez com que elas não fossem “forçadas” à limpeza, entrando na fila padrão concorrendo com milhares de outras.


Algumas ações que podem ajudar nesse tipo de cenário

  • manutenção periódica de índices

  • reavaliar estratégia de deletes em batches maiores

  • usar TRUNCATE quando aplicável

  • em alguns casos, recriar a tabela e mover apenas os dados necessários

  • forçar scan das tabelas para forçar o ghost cleanup (brincadeira rs, o rebuild ainda é uma opção melhor)


Está passando por esse tipo de problema na sua empresa? A Power Tuning oferece consultoria especializada em performance para Banco de Dados.

Fale com a gente: +55 27 3441-3060

Artigo desenvolvido por: Eduardo Rabelo (Tech Leader).

Power Tuning
Visão geral da privacidade

Este site utiliza cookies para que possamos lhe proporcionar a melhor experiência de usuário possível. As informações dos cookies são armazenadas em seu navegador e executam funções como reconhecê-lo quando você retorna ao nosso site e ajudar nossa equipe a entender quais seções do site você considera mais interessantes e úteis.