Eu tenho uma consulta um pouco complexa do SQL Server 2008 (cerca de 200 linhas de SQL bastante densa) que não estava funcionando conforme eu precisava. Com o tempo, o desempenho caiu de cerca de 0,5 segundos para cerca de 2 segundos.
Observando o plano de execução, era bastante óbvio que, ao reordenar as junções, o desempenho poderia ser melhorado. Eu fiz, e foi ... até cerca de 0,3 segundos. Agora a consulta tem a dica "OPTION FORCE ORDER" e a vida é boa.
Hoje vem-me hoje, limpando o banco de dados. Eu arquivo cerca de 20% das linhas, não realizando nenhuma ação no banco de dados relevante, exceto excluindo linhas ... o plano de execução é TOTALMENTE processado . Ele julga completamente quantas linhas determinadas subárvores retornarão e (por exemplo) substitui um:
<Hash>
com
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Agora, o tempo de consulta aumenta de cerca de 0,3s para cerca de 18s. (!) Só porque apaguei linhas. Se eu remover a dica de consulta, voltarei ao tempo de consulta de cerca de 2s. Melhor, mas pior.
Reproduzi o problema depois de restaurar o banco de dados em vários locais e servidores. Simplesmente excluir cerca de 20% das linhas de cada tabela sempre causa esse problema.
- É normal que uma ordem de junção forçada faça com que as estimativas da consulta sejam completamente imprecisas (e, portanto, imprevisíveis no tempo da consulta)?
- Devo apenas esperar que eu tenha que aceitar um desempenho de consulta abaixo do ideal ou assisti-lo como um falcão e editar manualmente as dicas de consulta? Ou talvez também indique todas as junções? .3s a 2s é um grande sucesso.
- É óbvio por que o otimizador explodiu após a exclusão de linhas? Por exemplo, "sim, foi necessária uma varredura de amostra e, como arquivei a maioria das linhas anteriormente no histórico de dados, a amostra produziu resultados esparsos e subestimou a necessidade de uma operação de hash classificada"?
Se você deseja ver os planos de execução, sugira um local para publicá-los. Caso contrário, eu experimentei a parte mais impressionante. Aqui está a estimativa incorreta fundamental, os números em parênteses são (estimados: reais) linhas.
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Observe que o loop interno deve verificar 908 linhas, mas verifica 52.258.441. Se fosse preciso, esse ramo teria cerca de 2 ms, em vez de 12 segundos. Antes de excluir as linhas, essa estimativa de junção interna era desativada apenas por um fator total de 2 e era executada como uma correspondência de hash em dois índices em cluster.