Quando uma consulta SQL anteriormente rápida começa a ficar lenta, onde procurar a origem do problema?


36

fundo

Eu tenho uma consulta em execução no SQL Server 2008 R2 que une e / ou une à esquerda cerca de 12 "tabelas" diferentes. O banco de dados é bastante grande, com muitas tabelas com mais de 50 milhões de linhas e cerca de 300 tabelas diferentes. É para uma empresa de grande porte que possui 10 armazéns em todo o país. Todos os armazéns lêem e gravam no banco de dados. Então é bem grande e muito ocupado.

A consulta com a qual estou tendo problemas é mais ou menos assim:

select t1.something, t2.something, etc.
from Table1 t1
    inner join Table2 t2 on t1.id = t2.t1id
    left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
    [etc]...
where t1.something = 123

Observe que uma das junções está em uma subconsulta não correlacionada.

O problema é que, a partir desta manhã, sem alterações (que eu ou qualquer pessoa da minha equipe conheça) no sistema, a consulta que normalmente leva cerca de 2 minutos para ser executada começa a demorar uma hora e meia para ser executada - quando correu de todo. O restante do banco de dados está funcionando bem. Tirei essa consulta do sproc em que ela normalmente é executada e em SSMS com variáveis ​​de parâmetro codificadas com a mesma lentidão.

A estranheza é que, quando pego a subconsulta não correlacionada e a jogo em uma tabela temporária, e depois a uso em vez da subconsulta, a consulta é executada corretamente. Além disso (e isso é o mais estranho para mim) se eu adicionar esse pedaço de código ao final da consulta, a consulta será ótima:

and t.name like '%'

Concluí (talvez incorretamente) dessas pequenas experiências que o motivo da desaceleração se deve à forma como o plano de execução em cache do SQL é configurado - quando a consulta é um pouco diferente, ela precisa criar um novo plano de execução.

Minha pergunta é a seguinte: quando uma consulta que costumava ser executada rapidamente repentinamente começa a ser executada lentamente no meio da noite e nada mais é afetado, exceto por essa consulta, como solucioná-lo e evitá-lo no futuro ? Como sei o que o SQL está fazendo internamente para torná-lo tão lento (se a consulta incorreta for executada, posso obter seu plano de execução, mas ele não será executado - talvez o plano de execução esperado me daria alguma coisa?)? Se esse problema ocorrer no plano de execução, como evito que o SQL pense que planos de execução realmente ruins são uma boa idéia?

Além disso, isso não é um problema com a detecção de parâmetros. Já vi isso antes, e não é isso, pois mesmo quando codifico as variáveis ​​no SSMS, ainda tenho desempenho lento.


Você poderia compartilhar o plano de consulta (o mais lento) aqui: brentozar.com/pastetheplan
MJH

Respostas:


31

Quando uma consulta que costumava ser executada rapidamente repentinamente começa a ser executada lentamente no meio da noite e nada mais é afetado, exceto por essa consulta, como solucioná-lo ...?

Você pode começar verificando se o plano de execução ainda está no cache. Verifique sys.dm_exec_query_stats, sys.dm_exec_procedure_statse sys.dm_exec_cached_plans. Se o plano de execução incorreto ainda estiver armazenado em cache, você poderá analisá-lo e também verificar as estatísticas de execução. As estatísticas de execução conterão informações como leituras lógicas, tempo de CPU e tempo de execução. Isso pode dar fortes indicações de qual é o problema (por exemplo, varredura grande x bloqueio). Veja Identificar consultas problemáticas para uma explicação de como interpretar os dados.

Além disso, isso não é um problema com a detecção de parâmetros. Já vi isso antes, e não é isso, pois mesmo quando codifico as variáveis ​​no SSMS, ainda tenho desempenho lento.

Não estou convencido. As variáveis ​​codificadas no SSMS não provam que o plano de execução incorreta passado não foi compilado em uma entrada distorcida. Leia Sniffing de parâmetros, incorporação e as opções RECOMPILE para obter um artigo muito bom sobre o assunto. Lento no aplicativo, rápido no SSMS? Compreender os mistérios do desempenho é outra excelente referência.

Concluí (talvez incorretamente) dessas pequenas experiências que o motivo da desaceleração se deve à forma como o plano de execução em cache do SQL é configurado - quando a consulta é um pouco diferente, ela precisa criar um novo plano de execução.

Isso pode ser facilmente testado. SET STATISTICS TIME ONmostrará o tempo de compilação versus execução. SQL Server: Os contadores de desempenho de estatísticas também revelam se a compilação é um problema (francamente, acho improvável).

No entanto, há algo semelhante que você pode acessar: o portão de concessão de consultas. Leia Entendendo a concessão de memória do servidor SQL para obter detalhes. Se sua consulta solicitar uma grande concessão no momento, não há memória disponível, ela terá que esperar e tudo parecerá como 'execução lenta' para o aplicativo. A análise das estatísticas das informações de espera revelará se esse é o caso.

Para uma discussão mais geral sobre o que medir e o que procurar, consulte Como analisar o desempenho do SQL Server


7

Esse é um problema da execução de consultas complexas no SQL Server. Felizmente, isso não acontece com tanta frequência.

Veja o plano de consulta para a consulta (quando ela estiver lenta). Suponho que você encontrará uma associação de loop aninhada ocorrendo uma ou mais vezes em tabelas sem índices para a associação. Isso realmente atrasa as coisas. Para avançar rapidamente, a maneira de corrigir isso é com uma dica. Adicione o seguinte no final da consulta:

OPTION (MERGE JOIN, HASH JOIN)

Isso geralmente corrigiu esse problema para mim no passado.

O que pode estar acontecendo é que alterações sutis na tabela (ou na disponibilidade de espaço temporário) fazem com que a otimização do SQL prefira um algoritmo de junção mais lento. Isso pode ser bastante sutil e repentino. Quando você cria uma tabela temporária, o otimizador tem mais informações sobre a tabela (como seu tamanho), para gerar um plano melhor.


1
O plano de execução está realmente usando uma junção de loop aninhada. No entanto, quando coloco a dica como você sugere, recebo o seguinte erro: "O processador de consultas não pôde produzir um plano de consulta devido às dicas definidas nesta consulta. Submeta novamente a consulta sem especificar dicas e sem usar SET FORCEPLAN." Quando adiciono OPTION (LOOP JOIN), é claro, ele cria um plano de execução, mas ainda tenho um problema com a execução lenta. Você já encontrou esse problema? Parece que ele precisa fazer loop de junção.

@Trevor. . . Não, eu realmente não vi esse problema. Talvez sua consulta esteja fazendo alguns não-equijoins (sem usar sinais de igual) e o otimizador precise usar junções de loop aninhadas lá.
Gordon Linoff

3

Geralmente, é um índice ausente que causa esse tipo de problema.

O que eu costumo fazer é executar a consulta usando o SQL Management Studio e ativar 'Incluir plano de execução real (CTRL + M)' e descobrir qual junção está apresentando a maior porcentagem.

O aplicativo não se concentra no gargalo, mas você pode encontrá-lo "rapidamente" apenas olhando para o resultado.

exemplo aqui: 48PercentForTop


2
um índice não vai de repente ir "faltando", embora, por isso, enquanto isso pode melhorar o desempenho não explica o problema
Fowl

3

Recentemente, experimentei esse mesmo problema que me levou a esta página.

@MartinSmith estava envolvido em algo quando recomendou atualizar suas estatísticas e explicar o plano. Gostaria de acrescentar que você também deve tentar garantir a execução de trabalhos / consultas que podem criar bloqueios e, assim, diminuir o tempo de resposta.

No meu caso, o culpado foi o trabalho de reunir estatísticas da tabela. Por alguma razão, ele não foi concluído na janela que deveria ter e continuou sendo executado quando os usuários foram reiniciados. Eu encontrei o processo, o matei e as consultas começaram a responder novamente.

Espero que isto ajude alguém


0

Você também precisa verificar se alguma tarefa de backup do servidor ou de Arquivamento \ indexação está em execução quando ocorrer um problema de desempenho no T-SQL \ Procedure.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.