Database
 sql >> Base de Dados >  >> RDS >> Database

Estatísticas de espera do joelho empurrão :PAGELATCH


Nos últimos 18 meses, concentrei-me em reações automáticas para esperar a análise de estatísticas e outros tópicos relacionados ao ajuste de desempenho, e neste post vou continuar isso e discutir o PAGELATCH_XX espera. O XX no final da espera significa que existem vários tipos de PAGELATCH espere, e os exemplos mais comuns são:
  • PAGELATCH_SH – ( SH estão) aguardando o acesso a uma página de arquivo de dados na memória para que o conteúdo da página possa ser lido
  • PAGELATCH_EX ou PAGELATCH_UP – (EX clusivo ou UP date) aguardando acesso a uma página de arquivo de dados na memória para que o conteúdo da página possa ser modificado

Quando um desses tipos de espera é o mais prevalente em um servidor, a reação instintiva é que o problema tem algo a ver com E/S (ou seja, confusão com o PAGEIOLATCH_XX wait type, que abordei em um post em 2014) e alguém tenta adicionar mais memória ou ajustar o subsistema de E/S. Nenhuma dessas reações terá qualquer efeito, pois as páginas do arquivo de dados sob contenção já estão na memória do buffer pool!

Em todos os casos, você pode ver se tem algum problema com PAGELATCH_XX contenção usando o sys.dm_os_waiting_tasks script no meu blog ou usando uma ferramenta como o Performance Advisor, conforme demonstrado (para um tipo de espera diferente) neste post.

Então, qual é a fonte da contenção? Primeiro, explicarei o histórico por trás desses tipos de espera e, em seguida, discutirei as duas causas mais comuns de PAGELATCH_XX contenção.

Plano de fundo:travas


Antes de entrar em algumas das causas de PAGELATCH_XX espera, eu quero explicar por que eles existem.

Em qualquer sistema multithread, as estruturas de dados que podem ser acessadas e manipuladas por vários threads precisam ser protegidas para evitar cenários como:
  • Dois threads atualizando uma estrutura de dados simultaneamente e algumas das atualizações são perdidas
  • Um encadeamento atualizando uma estrutura de dados simultaneamente com outro encadeamento lendo a estrutura de dados, então o encadeamento de leitura vê uma mistura de dados antigos e novos

Isso é ciência da computação básica, e o SQL Server não é diferente, portanto, todas as estruturas de dados dentro do SQL Server precisam ter controle de acesso multithread.

Um dos mecanismos que o SQL Server usa para fazer isso é chamado de trava, em que manter a trava no modo exclusivo impede que outros threads acessem a estrutura de dados e manter a trava no modo de compartilhamento impede que outros threads alterem a estrutura de dados. O SQL Server também usa spinlocks para algumas estruturas de dados e discuti isso neste post em 2014.

Mas por que uma página de arquivo de dados na memória é protegida por uma trava, você pode se perguntar? Bem, uma página de arquivo de dados é apenas uma estrutura de dados, embora de propósito especial, e, portanto, precisa dos mesmos controles de acesso que qualquer outra estrutura de dados. Portanto, quando um thread precisa modificar uma página de arquivo de dados, ele precisa adquirir uma trava exclusiva ou de atualização na página e, se não puder e precisar esperar, o tipo de espera PAGELATCH_EX ou PAGELATCH_UP resultados.

Contenção tempdb clássica


PAGELATCH a contenção em tempdb geralmente ocorre em bitmaps de alocação e ocorre com cargas de trabalho com muitas conexões simultâneas criando e descartando pequenas tabelas temporárias (que são armazenadas em tempdb).

Quando a primeira linha é inserida em uma tabela temporária, duas páginas devem ser alocadas (uma página de dados e uma página do IAM, que rastreia a página de dados). Essas páginas precisam ser marcadas como alocadas em uma página de alocação especial chamada página PFS e, por padrão, são alocadas a partir de extensões de dados especiais que são rastreadas por outra página de alocação chamada página SGAM (os detalhes sobre elas podem ser encontrados no meu antigo post do blog aqui). Quando a tabela temporária é eliminada, essas páginas precisam ser desalocadas novamente, necessitando de mais alterações nas páginas PFS e SGAM.

Se as tabelas temporárias forem pequenas e o tamanho cumulativo de todas as tabelas temporárias criadas simultaneamente for menor que 64 MB, todas essas alterações de bitmap de alocação serão centralizadas nas primeiras páginas PFS e SGAM no arquivo de dados tempdb (com ID de página (1:1) e (1:3) respectivamente). A atualização de uma dessas páginas de alocação requer o travamento da página, e apenas um encadeamento de cada vez pode estar alterando a página, portanto, todos os outros encadeamentos precisam esperar - com o tipo de espera PAGELATCH_UP .

Do SQL Server 2005 em diante, as tabelas temporárias podem ser armazenadas em cache quando descartadas, desde que tenham menos de 8 MB de tamanho (e no SQL Server 2014 não sejam criadas em um procedimento armazenado que também tenha instruções DDL na tabela temporária). Isso significa que o próximo thread que executa o mesmo plano de consulta pode retirar a tabela temporária do cache e não ter que lidar com as alocações iniciais. Isso reduz a contenção nos bitmaps de alocação, mas o cache de tabela temporária não é muito grande, portanto, cargas de trabalho com centenas de criações/remoções de tabelas temporárias simultâneas ainda terão muita contenção.

É trivial evitar a contenção nas páginas SGAM no tempdb habilitando o sinalizador de rastreamento documentado 1118 no servidor, que eu digo que deve ser habilitado em todos os servidores em todo o mundo e, na verdade, é o comportamento padrão imutável no SQL Server 2016.

Impedir a contenção nas páginas PFS no tempdb é um pouco mais difícil. Supondo que as tabelas temporárias sejam necessárias para o desempenho, o truque é ter vários arquivos de dados para tempdb para que as alocações sejam feitas em rodízio entre os arquivos, a contenção seja dividida em várias páginas PFS e, portanto, a contenção geral diminua. Infelizmente, não há uma resposta certa para quantos arquivos de dados você deve ter. Você pode ler mais sobre as orientações geralmente aceitas sobre isso no artigo KB 2154845 e nesta postagem do blog.

Inserir ponto de acesso


Em bancos de dados de usuários, uma causa comum de alto número de PAGELATCH_EX esperas é um hotspot de inserção.

Isso pode ocorrer quando uma tabela tem um índice clusterizado com uma chave de cluster int ou bigint e um tamanho de linha pequeno o suficiente para que muitas dezenas ou mais linhas de tabela possam caber em uma página de dados no nível folha do índice clusterizado.

Para tal tabela, se a carga de trabalho envolver muitas dezenas ou centenas de encadeamentos simultâneos inseridos na tabela, muitos dos encadeamentos gerarão linhas com valores de identidade (e, portanto, chaves de cluster) que precisam ser inseridas na mesma página de dados em nível de folha .

Agora lembre-se de que fazer qualquer alteração em uma página de arquivo de dados na memória requer uma trava exclusiva, portanto, cada uma das threads tentando inserir na mesma página deve adquirir a trava da página exclusivamente. Enquanto cada thread está segurando a trava exclusiva, os outros threads estarão esperando por PAGELATCH_EX para essa página, essencialmente tornando as inserções simultâneas em um processo síncrono extremamente engarrafado.

Existem algumas correções possíveis para esse problema:
  • Use uma chave mais aleatória e reconheça que isso levará à fragmentação do índice; portanto, use também um fator de preenchimento de índice para ajudar a evitar divisões de página
  • Espalhe as inserções na tabela usando algum tipo de mecanismo de particionamento artificial
  • Use um tamanho de linha de tabela mais longo (esta é obviamente a opção menos palatável)

Eu vi um ponto de acesso de inserção como esse surgir quando alguém tentou remover problemas de fragmentação de índice alterando uma chave de cluster GUID aleatória para uma chave de cluster de identidade int ou bigint, mas não conseguiu testar o novo esquema de tabela em cargas de produção.

Resumo


Assim como com outros tipos de espera, entender exatamente o que PAGELATCH_XX esperas médias é a chave para entender como solucioná-los.

No que diz respeito às estatísticas gerais de espera, você pode encontrar mais informações sobre como usá-las para solucionar problemas de desempenho em:
  • Minha série de postagens do blog SQLskills, começando com estatísticas de espera, ou por favor me diga onde dói
  • Minha biblioteca de tipos de espera e classes de trava aqui
  • Meu curso de treinamento online Pluralsight SQL Server:Solução de problemas de desempenho usando estatísticas de espera
  • Consultor de desempenho do SQL Sentry

Até a próxima, feliz solução de problemas!