Eu encontrei uma situação estranha em que o acréscimo OPTION (RECOMPILE)
à minha consulta faz com que ela seja executada em meio segundo, enquanto a omissão faz com que a consulta demore mais de cinco minutos.
Este é o caso quando a consulta é executada no Query Analyzer ou no meu programa C # via SqlCommand.ExecuteReader()
. Ligar (ou não ligar) DBCC FREEPROCCACHE
ou DBCC dropcleanbuffers
não faz diferença; Os resultados da consulta sempre são retornados instantaneamente com OPTION (RECOMPILE)
mais de cinco minutos sem ela. A consulta é sempre chamada com os mesmos parâmetros [para fins deste teste].
Estou usando o SQL Server 2008.
Estou bastante confortável em escrever SQL, mas nunca usei um OPTION
comando em uma consulta antes e não estava familiarizado com todo o conceito de caches de plano até verificar as postagens neste fórum. Meu entendimento das postagens é que OPTION (RECOMPILE)
é uma operação cara. Aparentemente, cria uma nova estratégia de pesquisa para a consulta. Então, por que as consultas subsequentes que omitem o OPTION (RECOMPILE)
são tão lentas? As consultas subsequentes não deveriam usar a estratégia de pesquisa que foi computada na chamada anterior, que incluía a dica de recompilação?
É altamente incomum ter uma consulta que exija uma dica de recompilação em cada chamada?
Desculpem a pergunta de nível de entrada, mas não consigo realmente entender isso.
UPDATE: me pediram para postar a consulta ...
select acctNo,min(date) earliestDate
from(
select acctNo,tradeDate as date
from datafeed_trans
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_money
where feedid=@feedID and feedDate=@feedDate
union
select acctNo,feedDate as date
from datafeed_jnl
where feedid=@feedID and feedDate=@feedDate
)t1
group by t1.acctNo
OPTION(RECOMPILE)
Ao executar o teste no Query Analyzer, acrescento as seguintes linhas:
declare @feedID int
select @feedID=20
declare @feedDate datetime
select @feedDate='1/2/2009'
Ao chamá-lo do meu programa C #, os parâmetros são passados através da SqlCommand.Parameters
propriedade
Para os fins desta discussão, você pode assumir que os parâmetros nunca mudam, para que possamos descartar o cheiro sub-ideal dos parâmetros como a causa.
fonte
X = @X OR @X IS NULL
deX=@X
e realizando uma busca Veja aqui ou empurrar predicados ainda mais para baixo contra uma exibição com funções da janelaRECOMPILE
. De qualquer forma, capture os planos de execução e observe as diferenças.Respostas:
Há momentos em que o uso
OPTION(RECOMPILE)
faz sentido. Na minha experiência, a única vez que essa é uma opção viável é quando você está usando SQL dinâmico. Antes de explorar se isso faz sentido na sua situação, recomendo reconstruir suas estatísticas. Isso pode ser feito executando o seguinte:E depois recrie seu plano de execução. Isso garantirá que, quando seu plano de execução for criado, ele usará as informações mais recentes.
A adição de
OPTION(RECOMPILE)
reconstruções do plano de execução sempre que sua consulta é executada. Nunca ouvi isso como descrito,creates a new lookup strategy
mas talvez estejamos apenas usando termos diferentes para a mesma coisa.Quando um procedimento armazenado é criado (suspeito que você esteja chamando ad-hoc sql do .NET, mas se você estiver usando uma consulta parametrizada, isso acabará sendo uma chamada de procedimento armazenado ), o SQL Server tentará determinar o plano de execução mais eficaz para essa consulta com base nos dados do seu banco de dados e nos parâmetros passados ( detecção de parâmetros ) e, em seguida, armazena em cache esse plano. Isso significa que, se você criar a consulta em que há 10 registros no banco de dados e executá-la quando houver 100.000.000 de registros, o plano de execução em cache poderá não ser mais eficaz.
Em resumo - não vejo nenhum motivo que
OPTION(RECOMPILE)
seja um benefício aqui. Eu suspeito que você só precisa atualizar suas estatísticas e seu plano de execução. A reconstrução de estatísticas pode ser uma parte essencial do trabalho do DBA, dependendo da sua situação. Se você ainda tiver problemas após atualizar suas estatísticas, sugiro postar os dois planos de execução.E para responder sua pergunta - sim, eu diria que é altamente incomum que sua melhor opção recompile o plano de execução toda vez que você executar a consulta.
fonte
OPTION (RECOMPILE)
pode ser a única solução.Muitas vezes, quando há uma diferença drástica de execução para execução de uma consulta, acho que essa é uma das cinco questões.
ESTATISTICAS- As estatísticas estão desatualizadas. Um banco de dados armazena estatísticas sobre o intervalo e a distribuição dos tipos de valores em várias colunas em tabelas e índices. Isso ajuda o mecanismo de consulta a desenvolver um "Plano" de ataque sobre como realizará a consulta, por exemplo, o tipo de método que ele usará para corresponder chaves entre tabelas usando um hash ou examinando o conjunto inteiro. Você pode chamar Estatísticas de atualização em todo o banco de dados ou apenas em determinadas tabelas ou índices. Isso reduz a velocidade da consulta de uma execução para outra porque, quando as estatísticas estão desatualizadas, é provável que o plano de consulta não seja ideal para os dados recém-inseridos ou alterados para a mesma consulta (explicado mais adiante mais adiante). Pode não ser adequado atualizar as estatísticas imediatamente em um banco de dados de produção, pois haverá sobrecarga, lentidão e atraso, dependendo da quantidade de dados a serem amostrados. Você também pode optar por usar uma verificação completa ou amostragem para atualizar as estatísticas. Se você olhar para o Plano de Consulta, também poderá visualizar as estatísticas nos Índices em uso, usando o comandoDBCC SHOW_STATISTICS (nome da tabela, nome do índice) . Isso mostrará a distribuição e os intervalos das chaves que o plano de consulta está usando para basear sua abordagem.
SNIFFING DE PARÂMETROS - O plano de consulta armazenado em cache não é ideal para os parâmetros específicos que você está passando, mesmo que a consulta em si não tenha sido alterada. Por exemplo, se você passar um parâmetro que recupera apenas 10 das 1.000.000 de linhas, o plano de consulta criado poderá usar uma Hash Join; no entanto, se o parâmetro que você passar usar 750.000 das 1.000.000 de linhas, o plano criado poderá ser um varredura de índice ou varredura de tabela. Em tal situação, você pode dizer à instrução SQL para usar a opção OPTION (RECOMPILE) ou um SP para usar WITH RECOMPILE. Dizer ao mecanismo que este é um "plano de uso único" e não usar um plano em cache que provavelmente não se aplica. Não existe uma regra sobre como tomar essa decisão, depende de saber como a consulta será usada pelos usuários.
ÍNDICES - É possível que a consulta não tenha sido alterada, mas uma alteração em outro lugar, como a remoção de um índice muito útil, diminuiu a velocidade da consulta.
LINHAS ALTERADAS - As linhas que você está consultando mudam drasticamente de uma chamada para outra. Normalmente, as estatísticas são atualizadas automaticamente nesses casos. No entanto, se você estiver criando SQL dinâmico ou chamando o SQL em um loop apertado, é possível que você esteja usando um Plano de Consulta desatualizado com base no número drástico de linhas ou estatísticas incorretas. Novamente, neste caso, OPTION (RECOMPILE) é útil.
A LÓGICA É a Lógica, sua consulta não é mais eficiente, era boa para um pequeno número de linhas, mas não era mais escalável. Isso geralmente envolve uma análise mais aprofundada do plano de consulta. Por exemplo, você não pode mais fazer coisas em massa, mas precisa fazer partes em pedaços e fazer Commits menores, ou seu produto cruzado foi bom para um conjunto menor, mas agora ocupa CPU e memória à medida que aumenta, isso também pode ser verdade para usando DISTINCT, você está chamando uma função para cada linha, suas correspondências de teclas não usam um índice por causa da conversão de tipo CASTING ou NULLS ou funções ... Muitas possibilidades aqui.
Em geral, ao escrever uma consulta, você deve ter uma imagem mental de como certos dados são distribuídos em sua tabela. Uma coluna, por exemplo, pode ter um número uniformemente distribuído de valores diferentes, ou pode ser distorcida, 80% das vezes possui um conjunto específico de valores, independentemente de a distribuição variar com frequência ao longo do tempo ou ser estática. Isso lhe dará uma idéia melhor de como criar uma consulta eficiente. Mas também quando o desempenho da consulta de depuração tem uma base para construir uma hipótese de por que é lenta ou ineficiente.
fonte
Para adicionar à excelente lista (fornecida por @CodeCowboyOrg) de situações em que OPTION (RECOMPILE) pode ser muito útil,
fonte
As primeiras ações antes de executar as consultas é desfragmentar / reconstruir os índices e as estatísticas, caso contrário você estará perdendo seu tempo.
Você deve verificar o plano de execução para ver se ele é estável (é o mesmo quando você altera os parâmetros); caso contrário, pode ser necessário criar um índice de cobertura (neste caso para cada tabela) (sabendo que sistema você pode criar um que também é útil para outras consultas).
como um exemplo: criar índice idx01_datafeed_trans No datafeed_trans (feedid, feedDate) INCLUDE (acctNo, tradeDate)
se o plano estiver estável ou você puder estabilizá-lo, execute a sentença com sp_executesql ('sql sentença') para salvar e usar um plano de execução fixo.
se o plano for instável, você precisará usar uma instrução ad-hoc ou EXEC ('sentença sql') para avaliar e criar um plano de execução a cada vez. (ou um procedimento armazenado "com recompilação").
Espero que ajude.
fonte
Necroing esta pergunta, mas há uma explicação que ninguém parece ter considerado.
ESTATÍSTICAS - As estatísticas não estão disponíveis ou são enganosas
Se todas as seguintes opções forem verdadeiras:
Em seguida, o servidor sql pode estar incorretamente assumindo que as colunas não estão correlacionadas, levando a estimativas de cardinalidade abaixo do esperado para aplicar restrições e um plano de execução ruim sendo selecionado. A correção nesse caso seria criar um objeto estatístico vinculando as duas colunas, o que não é uma operação cara.
fonte