Wie kann ich einen fehlerhaften Ausführungsplan aus der Azure SQL-Datenbank entfernen?

12

DBCC FREEPROCCACHEfunktioniert nicht in Azure SQL DB. Wie sonst kann ich einen Plan dazu zwingen, sich auf eine Weise aus dem Cache zu werfen, die einem Produktionssystem nicht schadet (dh ich kann nicht einfach ohne weiteres Tische wechseln)? Dies ist speziell für SQL gedacht, das von Entity Framework erstellt wurde. Es handelt sich also nicht um selbstverwaltete gespeicherte Prozesse, sondern um dynamisches SQL.

(Quelle waren schlechte Indizes -> schlechte Statistiken usw. Das ist alles behoben, aber ein schlechter Plan wird nicht verschwinden.)

UPDATE: Ich habe @ mrdennys Lösung ausgewählt, als er zuerst dort ankam. Ich verwende jedoch erfolgreich das Skript von @Aaron Bertrand, um die Arbeit auszuführen. Vielen Dank an alle für die Hilfe !!

Jaxidian
quelle
Können Sie eine sp_recompile in Azure ausführen?
Mrdenny
Ja. Auf was genau würde ich es laufen lassen? Wir haben keine gespeicherten Procs. Dies ist dynamisches SQL lief in sp_executesql.
Jaxidian
2
Sie können es auf dem Tisch selbst ausführen und das sollte die Pläne leeren, die diese Tabelle verwenden. (Wenn dies funktioniert, werde ich eine Antwort machen.)
Mrdenny
1
Ich habe das gerade an einer Tabelle versucht und es sperrt anscheinend die Tabelle in einer Transaktion während der Verarbeitung. Ich habe es an einem 10-Spalten-Tisch mit nur 24 Datensätzen versucht und es dauerte über eine Minute, bis es fertig war. In dieser Zeit konnte ich die Tabelle nicht abfragen. Ich kann so etwas auf unseren realen Tischen in der Produktion nicht ausführen!
Jaxidian
1
Verdammt, das ist ein Mist. Sieht so aus, als müssten Sie eine Schemaänderung wie das Hinzufügen einer nullfähigen Spalte vornehmen und diese dann löschen. Das löscht auch den Cache und sollte schnell gehen. Tests werden es mit Sicherheit zeigen.
Mrdenny

Antworten:

12

Azure SQL unterstützt dies jetzt direkt

Azure SQL-Datenbank unterstützt direkt das Löschen des Prozesscaches der aktuellen Benutzerdatenbank ohne Hacks:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

zusätzliche Information

Das folgende Skript (von Shannon Gowen ) kann verwendet werden, um den Prozess Schritt für Schritt zu beobachten:

-- 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
quelle
Ich habe dies noch nicht ausprobiert, aber wenn dies tatsächlich funktioniert, dann ist dies wahrscheinlich die "beste" Antwort ab Anfang 2017. Vielen Dank dafür - ich hatte keine Ahnung, dass dies da war! :-)
Jaxidian
Ich habe dies versucht (auf einer Premium-DB) und es hat funktioniert.
Remi Lemarchand
Ich habe dies als aktualisierte "Akzeptierte Antwort" markiert, dies jedoch noch nicht selbst getestet. Ich stütze mich dabei direkt auf das Feedback von Todd und Remi. Vielen Dank an alle!
Jaxidian
Nur um es nochmal zu überdenken, ich habe es benutzt und es hat gut für mich funktioniert! Ich füge ein paar zusätzliche Skripte zu Todd's Antwort hinzu, um es zu bereichern, aber sein Beitrag hat den Nagel auf den Kopf getroffen.
Jaxidian
Dies scheint bei mir nicht zu funktionieren - es wird nur ausgeführt, aber die Listen sind immer noch voll - ich bin auf SQL Azure - was kann falsch sein?
Dirk Boer
12

Es gibt heute keinen expliziten Weg, dies zu tun, aber das ist kein permanentes Szenario (der DBCC-Befehl wird immer noch nicht unterstützt, aber im Query Store nachgelesen ). Selbst wenn der Treffer für die Schemaänderung akzeptabel ist, kann es sein, dass er nicht Ihren Wünschen entspricht, da dadurch alle Pläne ungültig werden, die sich auf das zugrunde liegende Objekt beziehen, nicht nur das schlechte.

Dies nicht zu würdigen, aber es ist ziemlich einfach, dynamisches SQL zu erstellen, um denselben Vorgang für mehrere Tabellen auszuführen:

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;

(Ich habe einen Tipp zu diesem Thema "Länge von dynamischem SQL" geschrieben ...)

Aaron Bertrand
quelle
In meinem Fall ist es viel besser, sie alle zu entfernen, als die schlechten dort zu lassen. Danke für die Warnung. Ich weiß, dass Sie mir keine Funktionen mitteilen können, aber können Sie mir mitteilen, wann Sie nicht mehr darauf beschränkt sind, über Dinge zu sprechen, über die Sie nicht sprechen können? ;-)
Jaxidian
Das ist auch klassifiziert, sorry. :-)
Aaron Bertrand
Ich bin mir nicht sicher, was du mit dem Link meinst. Was ich damit gemeint habe ist, dass Ihre nvarchar(max)Variable nach 4000 Zeichen ein Limit erreicht, 8000 Zeichen, wenn ich es auf ändere varchar(max). Genau das Skript ausführen. Wir haben ~ 450 Tische, also schlagen wir das leicht (~ 30/60 Tische in). varchar(max)hat eine gültige Syntax, ist nur identisch mit varchar(8000)und nvarchar(max)ist identisch mit nvarchar(4000).
Jaxidian
3
Nun ja, wenn Sie PRINTden Befehl, zeigt es nur 8000 Bytes. Dies ist eine Einschränkung des PRINTBefehls und nicht von Azure. Wenn Sie den Befehl ausführen, funktioniert er auch dann, wenn Sie das Ganze nicht visuell überprüfen können.
Aaron Bertrand
... oh, sorry, ich denke du hast recht! Danke, dass du mich verbessert hast! Das ist, was passiert, wenn deine Frau vor 25 Minuten erwartet hat, dass du gehst ... ;-) Dieses Skript funktioniert perfekt für mich!
Jaxidian
6

Fügen Sie der Tabelle eine nullfähige Spalte hinzu, und löschen Sie die Spalte. Dadurch wird SQL gezwungen, den Cache für dieses Objekt zu leeren.

Wie bei allen Tabellen sollte ein Cursor den Trick ausführen. Verwenden Sie einfach einen Spaltennamen, der in keiner Tabelle vorhanden sein wird, z. B. 'zzzzzz_go_away' oder so.

mrdenny
quelle
4

Azure SQL-Datenbank wird derzeit nicht unterstützt DBCC FREEPROCCACHE, sodass Sie einen Ausführungsplan nicht manuell aus dem Cache entfernen können. Wenn Sie jedoch Änderungen an einer Tabelle oder Ansicht vornehmen, auf die die Abfrage ( ALTER TABLE/ ALTER VIEW) verweist, wird der Plan aus dem Cache entfernt. ( Referenz .)

Kin Shah
quelle
Ich wusste schon alles, was du hier gepostet hast. Dies ist weder eine gespeicherte Prozedur noch eine Ansicht, daher kann ich keine davon ändern. Wie kann ich meine Tabellen unter Last und ohne Ausfallzeiten oder Sperren der Tabelle unwesentlich ändern, um dies auszulösen?
Jaxidian
1
Sie können möglicherweise eine Dummy-Spalte hinzufügen und dann löschen. Dadurch wird der Plan aus dem Cache entfernt. Wie groß ist der Tisch?
Kin Shah
Das war die Lösung, wie von @mrdenny empfohlen. Danke für die Hilfe!! :-)
Jaxidian
1
Danke ... Nur ein paar Sekunden in der Zeit .. Beantwortete einen anderen Beitrag auf stackexchange ...
Kin Shah
1

Verwenden Sie Folgendes, um den gesamten Ausführungsplan zu löschen:

    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

Wenn Sie eine Tabelle oder Ansicht ändern, die darauf verweist, wird der Ausführungsplan gelöscht.

Ein bisschen mehr erklärt hier http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

Christian
quelle