Por que minha consulta repentinamente é mais lenta do que ontem?

76

[Saudações]

(marque uma)

[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,

Eu tenho um (marque todas as opções aplicáveis)

[ ] query [ ] stored procedure [ ] database thing maybe  

que estava funcionando bem (se aplicável)

[ ] yesterday [ ] in recent memory [ ] at some point 

mas de repente está mais lento agora.

Eu já verifiquei para garantir que ele não esteja sendo bloqueado e que não seja vítima de alguma tarefa de manutenção, relatório ou outro processo fora de banda.

Qual é o problema, o que devo fazer e quais informações posso fornecer para obter ajuda?

[*Insert appropriate closing remarks*]
Erik Darling
fonte

Respostas:

88

Caro [seu nome aqui]!

Oh não, desculpe-me por ouvir isso! Vamos começar com algumas noções básicas para que você se conserte rapidamente.

O que você encontra é chamado de Detecção de Parâmetros

É uma saída estranha e estranha. O nome sai da língua. Como a palavra alemã para esquilo.

E geralmente é seu amigo.

Quando uma consulta atinge seu servidor, um plano deve ser compilado. Para economizar tempo e recursos posteriormente, um plano de execução é armazenado em cache com base nas linhas estimadas que esse parâmetro fará com que seu código seja processado e retornado.

A maneira mais fácil de entender isso é imaginar um procedimento armazenado que precise contar coisas de duas populações desiguais.

Por exemplo:

  • Pessoas que usam camisas do CrossFit que não estão feridas: Zero

  • Pessoas que usam camisas CrossFit que estremecem quando estremecem: Todas

Obviamente, uma execução desse código teria muito mais trabalho que outra, e os planos de consulta que você desejaria realizar quantidades totalmente diferentes de trabalho pareceriam totalmente diferentes.

O que eu estou enfrentando?

Esse é um problema genuinamente difícil de encontrar, testar e corrigir.

  • É difícil de encontrar, porque isso não acontece de forma consistente
  • É difícil testar porque você precisa saber quais parâmetros causam planos diferentes
  • É difícil de corrigir, porque às vezes requer ajuste de consulta e índice
  • É difícil de corrigir, pois talvez você não consiga alterar consultas ou índices
  • É difícil de corrigir, porque mesmo que você altere consultas ou índices, ele ainda pode voltar

Correções rápidas

Às vezes, tudo que você precisa é de um pouco de clareza. Ou melhor, o cache do seu plano sim.

Se é um procedimento armazenado

Tente correr EXEC sys.sp_recompile @objname = N'schema.procname'. Isso fará com que o procedimento recompile um novo plano na próxima vez em que for executado.

O que isso não corrigirá:

  • Processos atualmente em execução.

O que isso não garante:

  • O próximo processo executado após a recompilação usará um parâmetro que fornece um bom plano.

Você também pode apontar sp_recompilepara uma tabela ou exibição, mas esteja avisado de que todo o código que tocar nessa tabela ou exibição será recompilado. Isso pode dificultar muito o problema.

Se é uma consulta parametrizada

Seu trabalho é um pouco mais difícil. Você precisará rastrear o identificador SQL. Você não deseja liberar todo o cache do plano - assim como usar sp_recompileem uma tabela ou exibição, você pode desencadear (ha ha ha) um monte de consequências indesejadas.

A maneira mais fácil de descobrir esse comando é executar sp_BlitzWho *! Há uma coluna chamada "fixar sniffing de parâmetros" que possui um comando para remover um único plano do cache. Isso tem as mesmas desvantagens da recompilação.

O que isso não corrigirá:

  • Processos atualmente em execução.

O que isso não garante:

  • O próximo processo executado após a recompilação usará um parâmetro que fornece um bom plano.

Eu ainda preciso de ajuda!

Vamos precisar do seguinte:

  • O bom plano de consulta, se possível
  • O plano de consulta incorreto
  • Os parâmetros usados
  • A consulta em questão
  • Definições de tabela e índice

Obtendo os planos de consulta e consulta

Se a consulta estiver em execução, você pode usar sp_BlitzWho * ou sp_WhoIsActive para capturar consultas em execução no momento.

EXEC sp_BlitzWho;

EXEC sp_WhoIsActive @get_plans = 1;

NUTS

Se a consulta não estiver em execução no momento, você pode procurá- la no cache do plano, usando sp_BlitzCache *.

Se você estiver no SQL Server 2016+ e tiver o Query Store ativado, poderá usar o sp_BlitzQueryStore *.

EXEC dbo.sp_BlitzCache @StoredProcName = 'Your Mom';

EXEC dbo.sp_BlitzQueryStore @StoredProcName = 'Your Mom';

Isso o ajudará a rastrear versões em cache do seu Procedimento Armazenado. Se for apenas um código parametrizado, sua pesquisa será um pouco mais difícil. Isso pode ajudar, no entanto:

EXEC dbo.sp_BlitzCache @QueryFilter = 'statement';

Você deve ver resultados bastante semelhantes de qualquer um deles. Novamente, o plano de consulta que convida a coluna clicky azul legal é seu amigo.

NUTS

A maneira mais fácil de compartilhar planos é usando Colar o plano * ou despejar o XML no pastebin. Para isso, clique em uma das colunas convidativas de clique azul. Seu plano de consulta deve aparecer em uma nova guia SSMS.

NUTS

Se você estiver interessado em compartilhar o código e a consulta da sua empresa, use a ferramenta Plan Explorer gratuita do Sentry One para anonimizar seu plano. Lembre-se de que isso dificulta a obtenção de ajuda - o código anonimizado é muito mais difícil de ler e descobrir.

Todas essas ferramentas sobre as quais falamos devem retornar o texto da consulta. Você não precisa fazer mais nada aqui.

Obter o (s) parâmetro (s) é um pouco mais difícil. Se você estiver usando o Plan Explorer , há uma guia na parte inferior que lista todos eles para você.

NUTS

Se você estiver usando sp_BlitzCache *, há uma coluna clicável que fornece a instrução de execução para procedimentos armazenados.

NUTS

Obtendo as Definições de Tabela e Índice

Você pode facilmente clicar com o botão direito do mouse no SSMS para criar um script.

NUTS

Se você deseja obter tudo de uma só vez, o sp_BlitzIndex * pode ajudar se você apontar diretamente para uma mesa.

EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
                       @SchemaName = 'dbo',
                       @TableName = 'Users';

Isso fornecerá a definição da tabela (embora não seja uma instrução create) e crie instruções para todos os seus índices.

Coletar e adicionar essas informações à sua pergunta deve fornecer às pessoas informações suficientes para ajudá-lo ou direcioná-lo na direção certa.

Eu quero fazer isso sozinho!

Bem, legal. Estou feliz por você. Você é uma pessoa louca.

Existem várias maneiras pelas quais as pessoas pensam "consertar" a detecção de parâmetros:

Mas isso realmente desabilita a detecção de parâmetros de maneiras diferentes. Isso não quer dizer que eles não possam resolver o problema, eles simplesmente não chegam à causa raiz.

Isso porque chegar à causa raiz geralmente é meio difícil. Você precisa procurar os "problemas de qualidade do plano" irritantes.

Começando com os planos rápidos vs lentos, procure diferenças como:

  • Índices usados
  • Ordem de adesão
  • Serial vs Parallel

Procure também operadores diferentes que tornam seu código sensível à detecção de parâmetros:

  • Pesquisas
  • Classifica
  • Tipo de associação
  • Concessões de memória (e, por extensão, derramamentos)
  • Carretéis

Não fique muito envolvido com a busca x varredura, a fragmentação do índice ou qualquer material que as pessoas cultuam e vasculham.

Geralmente, há um problema de indexação bastante básico. Às vezes, o código precisa ser reescrito um pouco.

Se você quiser saber mais sobre a detecção de parâmetros:

Se você está lendo isso e acha que perdi um link ou uma ferramenta útil, deixe um comentário. Eu farei o meu melhor para manter isso atualizado.


Erik Darling
fonte
28

A detecção de parâmetros não é a única causa possível para o desempenho variável de uma consulta. Qualquer um dos seguintes motivos comuns pode mostrar os mesmos sintomas:

  1. Distribuição / volume de dados alterados, cruzando um ponto de inflexão da decisão da árvore de pesquisa do otimizador
  2. Os índices / arquivos foram fragmentados
  3. As estatísticas foram atualizadas / adicionadas / descartadas ou tornaram-se obsoletas e enganosas devido a alterações nos dados
  4. Utilização de memória do Windows alterada
  5. Os logs de transações estão cheios e não estão truncando, causando expansão repetida de arquivos físicos
  6. Esquema alterado - índice / exibição / coluna / restrição indexada adicionada, modificada ou eliminada, tipo de dados alterado etc.
  7. Configurações de sinalizador de rastreamento alteradas
  8. Atualização do Windows foi aplicada
  9. Configuração do banco de dados ou servidor alterada
  10. Nível da CU do servidor alterado
  11. As configurações da sessão do aplicativo cliente foram alteradas

Os itens 6 a 11 desta lista só podem acontecer depois que alguma ação explícita foi tomada. Eu acho que você pretendia excluí-las, mas muitas vezes quem está enfrentando o desafio não sabe que alguém fez alterações, e vale a pena verificar isso antes de embarcar no caminho de limpar as entradas do cache do plano.

SQLRaptor
fonte
1
Obrigado pela edição Paul. @sp_BlitzErik - Não era minha intenção fornecer conselhos sobre tópicos específicos, apenas para aumentar a conscientização de que eles existem e que vale a pena conferir. Isso não significa que você diminua em relação ao seu excelente post. Você lidou com os parâmetros que aspiram profundamente, profissionalmente e com bom humor. Eu gostei de ler. Eu só quero ter certeza de que se alguém aqui visitar este post, seguindo o título cativante, ele / ela seja informado das possíveis causas alternativas. IMHO agrega valor à sua postagem, mas se você ainda quiser que eu a exclua, informe-me.
SQLRaptor 24/04
Não, não mesmo. Eu nunca pediria a alguém para excluir uma resposta incorreta ou prejudicial. Ainda acho que você poderia adicionar alguns detalhes, mas isso depende de você.
Erik Darling
10

Apenas para adicionar às respostas existentes, caso elas não ajudem, quando "de repente" suas consultas se comportarem de maneira diferente no dia seguinte, verifique:

  • O esquema para as tabelas usadas mudou desde a última vez? No caso do SSMS, você pode clicar com o botão direito do mouse no servidor no Pesquisador de Objetos e escolher Reports → Standard Reports → Schema Changes History.
  • A contagem de itens aumentou drasticamente? Talvez sua consulta seja muito mais lenta quando houver muitos dados nas tabelas usadas.
  • Alguém mais está utilizando o banco de dados ao mesmo tempo que você? Talvez escolha horários em que você não interfira no trabalho um do outro.
  • Como estão as estatísticas do sistema? Talvez o servidor esteja aquecendo e limitando a CPU ou os discos rígidos estejam ficando sem espaço ou trocados. Talvez haja outro problema de hardware, como incêndio ou inundação na sala do servidor.
user1306322
fonte
7

Outra possibilidade é que sua equipe de infraestrutura esteja usando ferramentas como o vMotion no VMware e a VM que suporta a instância do SQL esteja sendo movida sem problemas de host para host sem que o DBA saiba disso.

Este é um problema real quando sua infraestrutura é terceirizada ... Estou tendo um pesadelo real com ela.

pacificamente
fonte