web-dev-qa-db-fra.com

Comment supprimer un mauvais plan spécifique du cache de requêtes SQL Server?

Nous avons une requête SQL Server 2008 particulière (pas un proc stocké, mais la même chaîne SQL - s'exécute toutes les 5 minutes) qui met en cache par intermittence un très mauvais plan de requête.

Cette requête s'exécute normalement en quelques millisecondes, mais avec ce mauvais plan de requête, cela prend plus de 30 secondes.

Comment puis-je chirurgicalement supprimer uniquement le seul mauvais plan de requête mis en cache de SQL Server 2008, sans effacer tout le cache de requête sur le serveur de base de données de production?

33
Jeff Atwood

J'ai compris quelques trucs

select * from sys.dm_exec_query_stats

affichera tous les plans de requête mis en cache. Malheureusement, aucun texte SQL n'y est affiché.

Cependant, vous pouvez joindre le texte SQL aux plans comme suit:

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

À partir d'ici, il est assez simple d'ajouter une clause WHERE pour trouver le SQL que je connais dans la requête, puis je peux exécuter:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

pour supprimer chaque plan de requête du cache du plan de requête. Pas exactement facile ou pratique, mais cela apparaît pour fonctionner ..

edit: vider le cache de requête entier fonctionnera également, et est moins dangereux qu'il n'y paraît, du moins d'après mon expérience:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
39
Jeff Atwood

Si vous savez à quoi ressemble le bon plan, utilisez simplement n indice de plan .

Vous ne pouvez pas supprimer une entrée de cache spécifique, mais vous pouvez nettoyer un pool de cache entier avec DBCC FREESYSTEMCACHE(cachename/poolname) .

Vous pouvez obtenir le nom de cache d'un mauvais plan de requête si vous avez le descripteur de plan (à partir de sys.dm_exec_requests.plan_handle pour le session_id en difficulté pendant l'exécution, ou à partir de sys.dm_exec_query_stats = post-exécution):

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

Cependant, tous les plans SQL ont le nom "Plans SQL", ce qui rend le choix du bon pour DBCC FREESYSTEMCACHE un choix difficile.

Mise à jour

Peu importe, j'ai oublié DBCC FREEPROCCACHE(plan_handle), oui, cela fonctionnera.

6
Remus Rusanu

La solution FREEPROCCACHE est très bien, mais une façon plus directe de le faire est d'utiliser OPTION (RECOMPILE) sur votre chaîne SQL ( vous avez mentionné qu'il ne s'agissait pas d'un SP), cela indique au moteur qu'il s'agit d'un plan à usage unique, car vous pensez probablement qu'il y a un reniflement de paramètres ou vos statistiques sont radicalement différentes d'une exécution à l'autre et vous pensez que c'est un problème de plan mis en 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' 
1
CodeCowboyOrg