Estou tentando solucionar alguns picos de CPU intermitentes que estamos testemunhando em um de nossos SQL Servers de produção. Estamos executando o SQL Server 2008 R2 Standard Edition com 28 GB de RAM e 4 núcleos de CPU. Quando isso acontece, notamos um grande número de esperas RESOURCE_SEMAPHORE_QUERY_COMPILER, que duram cerca de um ou dois minutos e depois param, fazendo com que o uso da CPU volte ao normal.
Depois de pesquisar isso, entendo que isso normalmente é causado pela compilação de muitos planos de execução não reutilizáveis, para os quais estamos trabalhando atualmente em alterações em nosso aplicativo.
Esse comportamento também pode ser acionado por remoções de cache do plano devido à pressão de memória? Se sim, como eu verificaria isso? Estou tentando ver se há algum remédio de curto prazo que possamos fazer, como atualizar a RAM do servidor, até implantarmos nossas correções de aplicativos. A única outra opção de curto prazo em que consigo pensar é mover alguns de nossos bancos de dados mais ocupados para um servidor diferente.
Acredito que você verá esse sintoma se tiver MUITOS planos de consulta grandes que estão lutando por memória para compilar (isso tem muito pouco a ver com a execução da consulta em si). Para acertar isso, suspeito que você esteja usando um ORM ou algum tipo de aplicativo que gere muitas consultas exclusivas, mas relativamente complexas. O SQL Server pode estar sob pressão de memória devido a coisas como grandes operações de consulta, mas, pensando bem, é mais provável que seu sistema esteja configurado com muito menos memória do que precisa (ou nunca há memória suficiente para satisfazer todas as consultas que você 're tentando compilar, ou há outros processos na caixa que estão roubando memória do SQL Server).
Você pode dar uma olhada no que o SQL Server está configurado usando:
Você pode identificar os planos em cache que exigiram mais memória de compilação com a seguinte consulta de Jonathan Kehayias , ligeiramente adaptada:
Você pode ver como o cache do plano está sendo usado com o seguinte:
Quando você estiver enfrentando altas esperas de semáforo, verifique se esses resultados de consulta variam significativamente durante a atividade "normal":
E você também pode querer ver como a memória é distribuída:
E há algumas boas informações aqui sobre por que você pode estar vendo um grande número de compilações/recompilações (o que contribuirá para essa espera):
Você pode verificar se há altas contagens de compilação/recompilação usando os seguintes contadores:
E você pode verificar se há pressão de memória interna levando a despejos - contadores diferentes de zero aqui indicam que algo não é bom está acontecendo com o cache do plano:
OBSERVAÇÃO A maioria dessas métricas não tem uma mágica "oh meu Deus, preciso entrar em pânico ou fazer alguma coisa!" limite. O que você precisa fazer é fazer medições durante a atividade normal do sistema e determinar onde estão esses limites para seu hardware, configuração e carga de trabalho. Quando você entra em
pânico, faça alguma coisa é quando duas condições são verdadeiras:Optimize for ad hoc workloads
é uma ótima configuração para 99% das cargas de trabalho existentes, mas não será muito útil para reduzir os custos de compilação - visa reduzir o inchaço do cache do plano, impedindo que um plano de uso único armazene todo o plano até que seja executado duas vezes . Mesmo quando você armazena apenas o stub no cache do plano, ainda precisa compilar o plano completo para a execução da consulta. Talvez o que @Kahn quisesse recomendar fosse definir a parametrização no nível do banco de dados como forçada , o que potencialmente fornecerá uma melhor reutilização do plano (mas realmente depende de quão exclusivas são todas essas consultas de alto custo).Também algumas boas informações neste white paper sobre armazenamento em cache e compilação de planos.
De longe, o motivo mais comum pelo qual vi essas esperas aparecerem é resultado de índices fragmentados ou insuficientes e estatísticas que têm tamanho de amostra insuficiente ou são obsoletas. Isso resulta em verificações maciças de tabelas completas sobrecarregando toda a memória, o que, por sua vez, produz um sintoma que costumamos ver como RESOURCE_SEMAPHORE_QUERY_COMPILE.
A maneira mais fácil de verificar isso é verificar se as consultas executam varreduras completas de tabela/índice, quando deveriam estar fazendo buscas de índice. Se você tiver uma consulta de problema com a qual pode reproduzir o problema - torna-se muito fácil diagnosticar e corrigir isso.
Eu verificaria os índices nas tabelas afetadas por essas consultas problemáticas - ou seja. verifique a fragmentação do índice, possíveis índices filtrados que não são usados, índices ausentes que você pode querer criar, etc. Além disso, atualize suas estatísticas com FULLSCAN o mais rápido possível.
Um bom ponto a lembrar é que sua tabela de problemas pode não ser a única que precisa disso. Por exemplo, se você tem uma consulta que busca dados de 10 tabelas, o planejador de execução pode ocasionalmente mostrar que não está usando o índice da tabela 1, mas quando você verifica o índice da tabela 1, na verdade está ok. O planejador de consulta pode resolver buscar dados na tabela 1 com uma varredura completa da tabela corretamente, porque um índice com falha/insuficiente na tabela 7, por exemplo, retornou tantos dados que esta seria a opção mais rápida. Portanto, diagnosticar isso às vezes pode ser complicado.
Além disso, se você tiver muitas consultas code-behind com apenas algumas alterações nos valores das variáveis, por exemplo, convém verificar a ativação da otimização para cargas de trabalho ad hoc . Basicamente, o que ele faz é armazenar um esboço do plano compilado em vez do plano inteiro, economizando recursos quando você nunca obtém exatamente os mesmos planos todas as vezes.