¿Cómo elimino un plan incorrecto específico de la caché de consultas de SQL Server?

33

Tenemos una consulta particular de SQL Server 2008 (no un proceso almacenado, pero la misma cadena SQL, se ejecuta cada 5 minutos) que almacena en caché de forma intermitente un plan de consulta muy malo.

Esta consulta normalmente se ejecuta en unos pocos milisegundos, pero con este plan de consulta incorrecto, lleva más de 30 segundos.

¿Cómo elimino quirúrgicamente solo el plan de consulta en caché incorrecto de SQL Server 2008, sin eliminar toda la caché de consultas en el servidor de base de datos de producción?

Jeff Atwood
fuente

Respuestas:

39

Descubrí algunas cosas

select * from sys.dm_exec_query_stats

mostrará todos los planes de consulta en caché. Desafortunadamente, no se muestra texto SQL allí.

Sin embargo, puede unir el texto SQL a los planes así:

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

Desde aquí es bastante trivial agregar una WHEREcláusula para encontrar el SQL que sé que está en la consulta, y luego puedo ejecutar:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

para eliminar cada plan de consulta de la caché del plan de consulta. No es exactamente fácil o conveniente, pero parece funcionar ...

editar: volcar todo el caché de consultas también funcionará, y es menos peligroso de lo que parece, al menos en mi experiencia:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
Jeff Atwood
fuente
2
el consejo de usar una sugerencia de plan es, sin embargo, válido.
Remus Rusanu 05 de
1
Encontré esto después de que mi consulta actualizara mágicamente su mal plan, pero planeo probarlo la próxima vez. Una sugerencia de plan no ayuda si la consulta sufre de 'opcional-itis', donde tiene muchos parámetros opcionales y se ha optimizado para un conjunto, luego se ejecuta para un conjunto diferente. No hay un plan óptimo que se pueda adjuntar para este tipo de consulta. Hay un plan óptimo para un conjunto de parámetros que a su vez es horrible para otro conjunto de parámetros.
Nick.McDermaid
6

Si sabe cómo se ve el buen plan, simplemente use una sugerencia de plan .

No puede eliminar una entrada de caché específica, pero puede limpiar un grupo de caché completo con DBCC FREESYSTEMCACHE(cachename/poolname).

Puede obtener el nombre de caché de un plan de consulta incorrecto si tiene el identificador del plan (de sys.dm_exec_requests.plan_handle para el session_id en problemas durante la ejecución, o de sys.dm_exec_query_stats después de la ejecución):

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

Sin embargo, todos los planes SQL tienen el nombre 'Planes SQL', lo que hace que elegir el adecuado para DBCC FREESYSTEMCACHE sea una ... elección difícil.

Actualizar

No importa, se olvidó DBCC FREEPROCCACHE(plan_handle), sí, eso funcionará.

Remus Rusanu
fuente
1
La capacidad de pasar un plan_handle a DBCC FREEPROCCACHE está disponible en SQL Server 2008 y no en SQL Server 2005.
Mario
¿Qué significa si sys.dm_exec_cached_plansno tiene entrada para el plan_handledesde sys.dm_exec_requests?
Jonathan Gilbert
@JonathanGilbert significa que el plan no se almacenó en caché o se expulsó del caché. Ver docs.microsoft.com/en-us/sql/relational-databases/…
Remus Rusanu
Entonces, solo para confirmar, aunque recién comencé a ejecutar esa consulta , y la consulta no tiene indicios de que no la almacene en caché, ¿se puede deshabilitar porque SQL Server tomó la decisión de no almacenarla en caché? No sería porque todavía está funcionando, ¿verdad? Si decide almacenar en caché el plan, ¿se almacenará en caché desde el punto en el que la consulta comienza a ejecutarse?
Jonathan Gilbert
1

La solución FREEPROCCACHE está bien, pero una forma más directa de hacerlo es usar OPTION (RECOMPILE) en su cadena SQL (usted mencionó que no era un SP), esto le dice al motor que es un plan de uso único, porque probablemente sospeche hay un olfateo de parámetros o sus estadísticas son drásticamente diferentes de una ejecución a otra y sospecha que es un problema de plan en caché incorrecto.

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
fuente