Come rimuovo un piano specifico non valido dalla cache delle query di SQL Server?


33

Abbiamo una particolare query di SQL Server 2008 (non un proc memorizzato, ma la stessa stringa SQL - eseguita ogni 5 minuti) che memorizza a intermittenza un piano di query molto scadente.

Questa query normalmente viene eseguita in pochi millisecondi, ma con questo piano di query errato impiega più di 30 secondi.

Come rimuovere chirurgicamente solo un piano di query memorizzato nella cache errato da SQL Server 2008, senza eliminare l'intera cache delle query sul server del database di produzione?


Risposte:


39

Ho capito alcune cose

select * from sys.dm_exec_query_stats

mostrerà tutti i piani di query memorizzati nella cache. Sfortunatamente, non viene mostrato alcun testo SQL.

Tuttavia, puoi unire il testo SQL ai piani in questo modo:

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

Da qui è abbastanza banale aggiungere una WHEREclausola per trovare l'SQL che conosco sia nella query, e quindi posso eseguire:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

per rimuovere ciascun piano di query dalla cache del piano di query. Non esattamente facile o conveniente, ma sembra funzionare ..

modifica: il dumping dell'intera cache delle query funzionerà anche, ed è meno pericoloso di quanto sembri, almeno nella mia esperienza:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;

2
il consiglio di usare un suggerimento per il piano è comunque valido.
Remus Rusanu,

1
L'ho trovato dopo che la mia query è stata magicamente aggiornata, ma è un cattivo piano, ma ho intenzione di provarlo la prossima volta. Un suggerimento per il piano non aiuta se la query soffre di 'optional-itis' - dove ha molti parametri opzionali ed è stata ottimizzata per un set, quindi eseguita per un set diverso. Non esiste un piano ottimale che può essere allegato per questo tipo di query. Esiste un piano ottimale per un set di parametri che è a sua volta terribile per un altro set di parametri.
Nick.McDermaid,

6

Se sai come appare il buon piano, basta usare un suggerimento per il piano .

Non è possibile rimuovere una voce di cache specifica, ma è possibile pulire un intero pool di cache con DBCC FREESYSTEMCACHE(cachename/poolname).

È possibile ottenere il nome della cache di un piano di query non valido se si dispone dell'handle del piano (da sys.dm_exec_requests.plan_handle per session_id in difficoltà durante l'esecuzione o da sys.dm_exec_query_stats post esecuzione):

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

Tuttavia, tutti i piani SQL hanno il nome "Piani SQL" che rende la scelta di quello giusto per DBCC FREESYSTEMCACHE una ... scelta difficile.

Aggiornare

Non importa, dimenticato DBCC FREEPROCCACHE(plan_handle), sì, funzionerà.


1
La possibilità di passare un plan_handle a DBCC FREEPROCCACHE è disponibile in SQL Server 2008 e non in SQL Server 2005.
Mario,

Cosa significa se sys.dm_exec_cached_plansnon ha alcuna voce in esso per il plan_handleda sys.dm_exec_requests?
Jonathan Gilbert,

@JonathanGilbert significa che il piano non è stato memorizzato nella cache o è stato rimosso dalla cache. Vedi docs.microsoft.com/en-us/sql/relational-d database
Remus Rusanu

Quindi, solo per confermare, anche se ho appena iniziato a eseguire quella query e la query non ha alcun suggerimento che dice di non memorizzarla nella cache, può essere staccato perché SQL Server ha preso la decisione del valore di non memorizzarla nella cache? Non sarebbe perché è ancora in esecuzione, giusto? Se decide di memorizzare nella cache il piano, verrà memorizzato nella cache dal punto in cui inizia l' esecuzione della query ?
Jonathan Gilbert,

1

La soluzione FREEPROCCACHE va bene, ma un modo più diretto per farlo è usare OPTION (RECOMPILE) sulla tua stringa SQL (hai detto che non era un SP), questo dice al motore che è un piano monouso, perché probabilmente sospetti c'è Parameter Sniffing o le tue statistiche sono drasticamente diverse da corsa a corsa e sospetti che sia un problema di piano memorizzato nella cache.

DECLARE @SQL NVARCHAR(4000)
SELECT @SQL = 'SELECT * FROM Table WHERE Column LIKE @NAME OPTION (RECOMPILE)'
EXEC sp_executesql @SQL, N'@NAME varchar(15)', 'MyName' 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.