Para finalizar minha pequena série de artigos sobre travas, desta vez vou discutir algumas outras travas no SQL Server que você pode ver ocasionalmente, mas não merecem um artigo completo por si só. Como de costume, recomendo fortemente que você leia o post inicial da série antes deste, para que você tenha todo o conhecimento geral sobre travas.
A trava LOG_MANAGER
A trava LOG_MANAGER é utilizada para sincronização durante algumas operações envolvendo o log de transações, e há uma trava LOG_MANAGER por banco de dados (pois cada banco de dados possui seu próprio gerenciador de log). Ele só pode ser adquirido no modo exclusivo e pode ser um gargalo durante o crescimento do arquivo de log de transações. O cenário em que se tornará evidente como um problema é:
- O arquivo de log tem um pequeno conjunto de crescimento automático
- Existem muitas conexões simultâneas gerando registros de log de transações
- O arquivo de log continua crescendo
Quando o arquivo de log ficar sem espaço, ele precisará crescer. O primeiro encadeamento para obter mais espaço de log é necessário adquire a trava LOG_MANAGER no modo EX e prossegue para aumentar o arquivo de log. Muitos outros encadeamentos continuam tentando gerar registros de log e entrar na fila para a trava LOG_MANAGER, para que possam aumentar o arquivo de log. Quando o primeiro thread libera o latch, o próximo o pega e percebe que o log já cresceu, então o descarta e continua. E assim por diante e assim por diante. Aliás, esse padrão de gargalo é chamado de comboio de trava .
Você pode pensar nisso exatamente como o mesmo gargalo que com a trava FGCB_ADD_REMOVE que discuti anteriormente na série, mas com o crescimento do arquivo de log em vez do crescimento do arquivo de dados. No entanto, com o latch FGCB_ADD_REMOVE, geralmente a instância tem a inicialização instantânea de arquivos habilitada, então o crescimento do arquivo é muito rápido, mas com o latch LOG_MANAGER, o log *deve* ser inicializado com zero, e o tempo perdido na fila de latch é maior .
A solução para este gargalo tem três partes:
- Defina o crescimento automático do arquivo de log corretamente, para que o log não cresça com frequência
- Dimensione o log corretamente para a carga de trabalho, para que o log não cresça de forma alguma
- Verifique se o log está limpando corretamente, para que o log não precise crescer
Se tudo isso estiver no lugar, você não deve ver a trava LOG_MANAGER ser um gargalo regular, e falo mais sobre isso no meu post aqui.
A trava ACCESS_METHODS_DATASET_PARENT
Quando um heap ou um índice está sendo acessado, internamente há um objeto chamado HeapDataSetSession ou IndexDataSetSession, respectivamente. Quando uma varredura paralela está sendo executada, as threads que realizam o trabalho real da varredura têm, cada uma, um conjunto de dados “filho” (outra instância dos dois objetos que acabei de descrever), e o conjunto de dados principal, que está realmente controlando a varredura, é chamado o “pai”.
Quando um dos threads de trabalho de varredura esgota o conjunto de linhas que deveria varrer, ele precisa obter um novo intervalo acessando o conjunto de dados pai, o que significa adquirir a trava ACCESS_METHODS_DATASET_PARENT no modo exclusivo. Embora isso possa parecer um gargalo, na verdade não é, e não há nada que você possa fazer para impedir que os threads que executam uma verificação paralela mostrem ocasionalmente uma espera LATCH_EX por essa trava.
A pergunta que você deve estar se perguntando é:essa consulta deve estar executando uma verificação paralela em primeiro lugar? É perfeitamente possível que algo tenha acontecido para forçar o plano de consulta a incluir uma verificação paralela quando essa pode não ser a maneira mais eficiente de executar a consulta. Exemplos de coisas que podem fazer com que um plano mude para uma verificação paralela incluem:
- Estatísticas desatualizadas
- Um índice não clusterizado ausente ou descartado
- Novo código forçando uma verificação devido a uma conversão implícita — uma incompatibilidade de tipo de dados entre uma coluna e uma variável/parâmetro, que impede o uso de um índice não clusterizado
- Novo código forçando uma verificação porque a aritmética está sendo executada em uma coluna da tabela em vez de uma variável/parâmetro, o que novamente impede o uso de um índice não clusterizado
- O crescimento de dados ocorre e uma verificação é realmente o plano mais eficiente
Ou pode ser que essa consulta exija uma varredura, caso em que LATCH_EX espera por ACCESS_METHODS_DATASET_PARENT são apenas parte do seu ambiente.
A trava ACCESS_METHODS_HOBT_VIRTUAL_ROOT
Cada instância dessa trava protege uma entrada nos metadados do Storage Engine para uma b-tree, especificamente o ID da página raiz da b-tree (a página na parte superior do triângulo que geralmente consideramos um índice) . Estou dizendo especificamente b-tree e não índice , pois um índice pode ter várias partições, cada uma com uma b-tree (essencialmente uma parte do índice geral, mas com restrições de chave de valor baixo e alto).
Toda vez que um thread precisa percorrer uma b-tree, ele deve começar na página raiz e descer até o nível folha. Para ler os metadados que contêm o ID da página raiz, o encadeamento deve adquirir a trava ACCESS_METHODS_HOBT_VIRTUAL_ROOT no modo SH, para garantir que o ID da página não esteja em processo de alteração. Quando um thread precisa alterar o ID da página raiz, ele deve adquirir a trava no modo EX.
Por que a página raiz de uma b-tree mudaria? À medida que o número de registros de índice na página raiz aumenta, eventualmente ela será preenchida e ocorrerá uma divisão de página. Quando isso acontece, a página raiz atual e a página em que ela se divide tornam-se um novo nível na árvore b, e uma página raiz totalmente nova é criada, com dois registros de índice, apontando para a página raiz antiga e a página que ela contém. dividir em. O novo ID da página raiz deve ser inserido nos metadados, para que a trava seja adquirida no modo EX. Isso acontecerá algumas vezes rapidamente, pois um índice em uma tabela vazia começa a ser preenchido por inserções, mas não é algo que você verá como um problema de gargalo de desempenho contínuo.
Resumo
Como tenho certeza que você aprendeu nesta série, entender travas e gargalos de trava envolve saber um pouco mais sobre o que está acontecendo dentro do Storage Engine do que para análise geral de estatísticas de espera.
Eu costumo aconselhar as pessoas *não* a iniciar a solução de problemas de desempenho examinando as estatísticas de travamento (via sys.dm_os_latch_stats ), mas sempre começar com estatísticas de espera (veja minha postagem aqui) e apenas se aprofundar nas travas se LATCH_EX ou LATCH_SH forem uma das principais esperas na instância do SQL Server.
Se você tiver alguma dúvida sobre travas, sinta-se à vontade para me enviar uma linha.