Como removo um plano incorreto específico do cache de consulta do SQL Server?

33

Temos uma consulta específica do SQL Server 2008 (não um processo armazenado, mas a mesma sequência SQL - é executada a cada 5 minutos) que armazena em cache intermitentemente um plano de consulta muito ruim.

Essa consulta normalmente é executada em alguns milissegundos, mas com esse plano de consulta incorreto, leva mais de 30 segundos.

Como removo cirurgicamente apenas um plano de consulta em cache incorreto do SQL Server 2008, sem remover todo o cache de consulta no servidor de banco de dados de produção?

Jeff Atwood
fonte

Respostas:

39

Eu descobri algumas coisas

select * from sys.dm_exec_query_stats

mostrará todos os planos de consulta em cache. Infelizmente, nenhum texto SQL é mostrado lá.

No entanto, você pode associar o texto SQL aos planos da seguinte maneira:

select plan_handle, creation_time, last_execution_time, execution_count, qt.text
FROM 
   sys.dm_exec_query_stats qs
   CROSS APPLY sys.dm_exec_sql_text (qs.[sql_handle]) AS qt

A partir daqui, é bastante trivial adicionar uma WHEREcláusula para encontrar o SQL que eu sei que está na consulta e então eu posso executar:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

para remover cada plano de consulta do cache do plano de consulta. Não é exatamente fácil ou conveniente, mas parece funcionar ..

edit: despejar todo o cache de consulta também funcionará e é menos perigoso do que parece, pelo menos na minha experiência:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
Jeff Atwood
fonte
2
o conselho para usar uma dica de plano permanece, no entanto.
Remus Rusanu
11
Descobri isso depois que minha consulta atualizou magicamente seu plano ruim, mas pretendo testá-lo na próxima vez. Uma dica de plano não ajuda se a consulta sofre de 'optional-itis' - onde possui muitos parâmetros opcionais e foi otimizada para um conjunto, depois execute para um conjunto diferente. Não há um plano ideal que possa ser anexado para esse tipo de consulta. Existe um plano ideal para um conjunto de parâmetros que, por sua vez, é péssimo para outro conjunto de parâmetros.
Nick.McDermaid
6

Se você sabe como é o bom plano, use uma dica de plano .

Você não pode remover uma entrada de cache específica, mas pode limpar um conjunto de cache inteiro DBCC FREESYSTEMCACHE(cachename/poolname).

Você pode obter o nome do cache de um plano de consulta incorreto se tiver o identificador do plano (em sys.dm_exec_requests.plan_handle para o session_id com problemas durante a execução ou em sys.dm_exec_query_stats após a execução):

select ce.name
from sys.dm_exec_cached_plans cp
join sys.dm_os_memory_cache_entries ce on cp.memory_object_address = ce.memory_object_address
where cp.plan_handle = @bad_plan

No entanto, todos os planos SQL têm o nome 'SQL Plans', o que torna a escolha certa para o DBCC FREESYSTEMCACHE uma escolha difícil.

Atualizar

Deixa pra lá, esqueci DBCC FREEPROCCACHE(plan_handle), sim, isso vai funcionar.

Remus Rusanu
fonte
11
A capacidade de passar um plan_handle para DBCC FREEPROCCACHE está disponível em SQL Server 2008 e não no SQL Server 2005.
Mario
O que significa se sys.dm_exec_cached_plansnão houver nenhuma entrada para o plan_handlefrom sys.dm_exec_requests?
Jonathan Gilbert
@ JonathanGilbert significa que o plano não foi armazenado em cache ou foi despejado do cache. Consulte docs.microsoft.com/en-us/sql/relational-databases/…
Remus Rusanu
Então, só para confirmar, mesmo que eu tenha começado a executar essa consulta e a consulta não tenha nenhuma dica para não armazená-la em cache, ela pode ser desfeita em cache porque o SQL Server tomou a decisão de valor para não armazená-la em cache? Não seria porque ainda está funcionando, certo? Se ele decidir armazenar em cache o plano, ele será armazenado em cache desde o ponto em que a consulta começa a ser executada?
Jonathan Gilbert
1

O FREEPROCCACHE solução é boa, mas uma maneira mais direta de fazer isso é usar OPTION (RECOMPILE) em sua String SQL (você mencionou que não era um SP); isso informa ao mecanismo que é um plano de uso único, porque provavelmente você suspeita há Detecção de Parâmetros ou suas Estatísticas são drasticamente diferentes de execução para execução e você suspeita que seja um problema de Plano em Cache Incorreto.

DECLARE @SQL NVARCHAR(4000)
SELECT @SQL = 'SELECT * FROM Table WHERE Column LIKE @NAME OPTION (RECOMPILE)'
EXEC sp_executesql @SQL, N'@NAME varchar(15)', 'MyName' 
CodeCowboyOrg
fonte