Comment supprimer un mauvais plan d'exécution d'Azure SQL Database?

12

DBCC FREEPROCCACHEne fonctionne pas dans Azure SQL DB. Sinon, comment puis-je forcer un plan à se retirer du cache d'une manière qui ne nuira pas à un système de production (c'est-à-dire que je ne peux pas simplement modifier les tables à volonté)? Ceci est spécifiquement pour SQL créé par Entity Framework, donc ce ne sont pas des procs stockés autogérés - c'est effectivement du SQL dynamique.

(La source était de mauvais index -> de mauvaises statistiques, etc. Tout est corrigé, mais un mauvais plan ne disparaîtra pas.)

MISE À JOUR: J'ai choisi la solution de @ mrdenny comme il est arrivé en premier. Cependant, j'utilise avec succès le script de @Aaron Bertrand pour effectuer le travail. Merci à tous pour l'aide !!

Jaxidian
la source
Pouvez-vous faire un sp_recompile dans Azure?
mrdenny
Oui. Sur quoi pourrais-je l'exécuter? Nous n'avons aucun proc stocké. Il s'agit de SQL dynamique sp_executesql.
Jaxidian
2
Vous pouvez l'exécuter sur la table elle-même et cela devrait vider les plans qui utilisent cette table. (Si cela fonctionne, je vais en faire une réponse.)
mrdenny
1
J'ai juste essayé ceci sur une table et cela verrouille apparemment la table dans une transaction pendant le traitement. Je l'ai essayé sur une table à 10 colonnes avec seulement 24 enregistrements et cela a pris plus d'une minute pour terminer. Pendant ce temps, je n'ai pas pu interroger la table. Je ne peux pas exécuter quelque chose comme ça sur nos vraies tables en production!
Jaxidian
1
Merde, c'est une déception. Il semble que vous devrez effectuer un changement de schéma, comme ajouter une colonne nullable, puis la supprimer. Cela effacera également le cache et devrait être rapide. Les tests le diront à coup sûr.
mrdenny

Réponses:

12

Azure SQL prend désormais directement en charge cette

Azure SQL Database prend directement en charge la suppression du cache de proc de la base de données utilisateur actuelle sans aucun piratage:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

Information additionnelle

Le script suivant (par Shannon Gowen ) peut être utilisé pour regarder le processus étape par étape:

-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;

-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;

-- list available plans
select * from sys.dm_exec_cached_plans;
Todd Menier
la source
Je n'ai pas encore essayé cela mais si cela est en fait fonctionnel, alors c'est probablement la "meilleure" réponse au début de 2017. Merci pour cela - je n'avais aucune idée que c'était là! :-)
Jaxidian
J'ai essayé cela (sur une base de données Premium) et cela a fonctionné.
Remi Lemarchand
J'ai signalé cela comme une «réponse acceptée» mise à jour, mais je ne l'ai pas encore testé moi-même. Je fonde cela directement sur les commentaires de Todd et Remi. Merci a tous!
Jaxidian
Juste pour revisiter, je l'ai utilisé et cela a bien fonctionné pour moi! J'ajoute quelques scripts supplémentaires à la réponse de Todd ici pour l'enrichir, mais son message a mis le doigt sur la tête.
Jaxidian
Cela ne semble pas fonctionner pour moi - il s'exécute juste mais les listes sont toujours pleines - je suis sur SQL Azure - qu'est-ce qui peut être faux?
Dirk Boer
12

Il n'y a pas de moyen explicite de le faire aujourd'hui, mais ce n'est pas un scénario permanent (la commande DBCC n'est toujours pas prise en charge, mais lisez sur Query Store ). Même lorsque le hit de changement de schéma est acceptable, il peut ne pas être ce que vous voulez, car il invalidera tous les plans liés à l'objet sous-jacent, pas seulement le mauvais.

Ne pas chercher de crédit pour cela, mais créer du SQL dynamique pour effectuer la même opération sur plusieurs tables est assez facile:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE '
  + QUOTENAME(SCHEMA_NAME([schema_id])) 
  + '.' + QUOTENAME(name) + ' ADD fake_column INT NULL;
  ALTER TABLE ' 
  + QUOTENAME(SCHEMA_NAME([schema_id]))
  + '.' + QUOTENAME(name) + ' DROP COLUMN fake_column;'
FROM sys.tables
--WHERE name IN, LIKE, etc.

PRINT @sql;

-- if the command > 8K, you can see the second chunk e.g.

PRINT SUBSTRING(@sql, 8001, 8000);

--EXEC sys.sp_executesql @sql;

(J'ai écrit un conseil sur ce problème de "longueur du SQL dynamique" ...)

Aaron Bertrand
la source
Dans mon cas, il est préférable de les supprimer tous plutôt que de laisser les mauvais dedans. Merci pour l'information. Je sais que vous ne pouvez pas me dire les fonctionnalités mais pouvez-vous me dire quand vous pourriez ne plus être limité à parler de choses dont vous ne pouvez pas parler? ;-)
Jaxidian
C'est aussi classifié, désolé. :-)
Aaron Bertrand
Je ne sais pas ce que vous entendez par le lien. Ce que je voulais dire, c'est que votre nvarchar(max)variable atteint une limite après 4000 caractères, 8000 caractères si je la change varchar(max). Exécuter ce script exact. Nous avons ~ 450 tables, donc nous avons atteint facilement (~ 30/60 tables). varchar(max)est une syntaxe valide, elle est juste identique à varchar(8000)et nvarchar(max)est identique à nvarchar(4000).
Jaxidian
3
Eh bien oui, lorsque vous PRINTla commande, elle n'affiche que 8000 octets. C'est une limitation de la PRINTcommande, pas Azure. Si vous exécutez la commande, cela fonctionnera même si vous ne pouvez pas inspecter visuellement le tout.
Aaron Bertrand
... doh, désolé, je pense que tu as raison! Merci de m'avoir corrigé! C'est ce qui arrive quand ta femme s'attendait à ce que tu partes il y a 25 minutes ... ;-) Ce script fonctionne parfaitement pour moi!
Jaxidian
6

Ajoutez une colonne nullable au tableau, puis supprimez la colonne. Cela forcera SQL à vider le cache de cet objet.

Quant à faire tous les tableaux, un curseur devrait faire l'affaire. Utilisez simplement un nom de colonne qui n'existera jamais dans aucune table comme 'zzzzzz_go_away' ou quelque chose.

mrdenny
la source
4

Azure SQL Database ne prend actuellement pas en charge DBCC FREEPROCCACHE, vous ne pouvez donc pas supprimer manuellement un plan d'exécution du cache. Cependant, si vous apportez des modifications à une table ou à une vue référencée par la requête ( ALTER TABLE/ ALTER VIEW), le plan sera supprimé du cache. ( Référence .)

Kin Shah
la source
Je savais déjà tout ce que tu as posté ici. Ce n'est ni une procédure stockée ni une vue, je ne peux donc pas en modifier une. Comment pourrais-je modifier mes tables de manière insignifiante, sous charge et sans provoquer d'interruption ou de verrouillage de la table, pour déclencher cela?
Jaxidian
1
Vous pouvez éventuellement ajouter une colonne factice, puis la supprimer. Cela supprimera le plan du cache. Quelle est la taille de la table?
Kin Shah
Cela a fini par être la solution, comme l'a recommandé @mrdenny. Merci pour l'aide!! :-)
Jaxidian
1
Merci ... Juste quelques secondes dans le temps .. Répondais à un autre message sur stackexchange ...
Kin Shah
1

Pour effacer tout le plan d'exécution, utilisez ceci:

    SET NOCOUNT ON

DECLARE @lcl_name VARCHAR(100)
DECLARE @addcolumnSql nVARCHAR(MAX)
DECLARE @dropcolumnSql nVARCHAR(MAX)

DECLARE cur_name CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
OPEN cur_name
FETCH NEXT FROM cur_name INTO @lcl_name
WHILE @@Fetch_status = 0
BEGIN
set @addcolumnSql = 'alter table [' + @lcl_name + '] add temp_col_to_clear_exec_plan bit'
EXEcute sp_executesql @addcolumnSql
print @addcolumnSql
set @dropcolumnSql = 'alter table [' + @lcl_name + '] drop column temp_col_to_clear_exec_plan'
EXEcute sp_executesql @dropcolumnSql
print @dropcolumnSql
--  EXEC (@lcl_name )
FETCH NEXT FROM cur_name INTO @lcl_name
END
CLOSE cur_name
DEALLOCATE cur_name
SET NOCOUNT OFF

Si vous modifiez une table ou une vue qui y fait référence, le plan d'exécution est effacé.

Un peu plus expliqué ici http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

Christian
la source