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.