Come posso rimuovere un piano di esecuzione errata dal database SQL di Azure?


12

DBCC FREEPROCCACHEnon funziona in Azure SQL DB. In quale altro modo posso forzare un piano a buttarsi fuori dalla cache in un modo che non danneggi un sistema di produzione (cioè non posso semplicemente andare a modificare le tabelle volenti o nolenti)? Questo è specificamente per SQL creato da Entity Framework, quindi non si tratta di processi memorizzati autogestiti: è effettivamente un SQL dinamico.

(La fonte era indici cattivi -> cattive statistiche, ecc. È tutto risolto, ma un piano cattivo non andrà via.)

AGGIORNAMENTO: Ho scelto la soluzione di @ mrdenny appena arrivata lì. Tuttavia, sto usando con successo la sceneggiatura di @Aaron Bertrand per eseguire il lavoro. Grazie a tutti per l'aiuto !!


Puoi fare uno sp_recompile in Azure?
mrdenny,

Sì. Su cosa lo farei esattamente? Non abbiamo procs memorizzati. Questo è SQL dinamico eseguito sp_executesql.
Jaxidian,

2
Puoi eseguirlo sul tavolo da solo e questo dovrebbe svuotare i piani che usano quel tavolo. (Se funziona, lo farò una risposta.)
mrdenny

1
Ho appena provato questo su un tavolo e apparentemente blocca il tavolo in una transazione durante l'elaborazione. L'ho provato su una tabella a 10 colonne con solo 24 record e ho impiegato più di un minuto per terminare. Durante questo periodo, non sono stato in grado di interrogare la tabella. Non posso eseguire qualcosa del genere sui nostri veri tavoli in Production!
Jaxidian,

1
Accidenti, è un peccato. Sembra che dovrai fare una modifica dello schema come aggiungere una colonna nullable, quindi rilasciarla. Anche questo cancellerà la cache e dovrebbe essere veloce. I test lo diranno per certo.
mrdenny,

Risposte:


12

Azure SQL ora supporta direttamente questo

Il database SQL di Azure supporta direttamente la cancellazione della cache proc del database utente corrente senza alcun hack:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

Informazioni aggiuntive

Il seguente script (di Shannon Gowen ) può essere utilizzato per seguire il processo passo dopo passo:

-- 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;

Non l'ho ancora provato, ma se questo è effettivamente funzionale, allora questa è probabilmente la risposta "migliore" all'inizio del 2017. Grazie per questo - non avevo idea che fosse lì! :-)
Jaxidian,

Ho provato questo (su un DB Premium) e ha funzionato.
Remi Lemarchand,

Ho segnalato questo come una "Risposta accettata" aggiornata ma non l'ho ancora testato da solo. Lo sto basando direttamente sul feedback di Todd e Remi. Ringrazia tutti!
Jaxidian,

Solo per rivisitare, l'ho usato e ha funzionato bene per me! Sto aggiungendo alcuni script aggiuntivi alla risposta di Todd qui per arricchirla, ma il suo post ha colpito l'unghia sulla testa.
Jaxidian,

Questo non sembra funzionare per me - si esegue solo ma gli elenchi sono ancora pieni - Sono su SQL Azure - cosa può essere sbagliato?
Dirk Boer,

12

Non esiste un modo esplicito per farlo oggi, ma questo non è uno scenario permanente (il comando DBCC non è ancora supportato, ma può essere letto su Query Store ). Anche quando l'hit di modifica dello schema è accettabile, potrebbe non essere quello che vuoi, perché invaliderà tutti i piani relativi all'oggetto sottostante, non solo quello cattivo.

Non cercare credito per questo, ma creare SQL dinamico per eseguire la stessa operazione su più tabelle è abbastanza semplice:

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;

(Ho scritto un suggerimento su questo problema "lunghezza di SQL dinamico" ...)


Nel mio caso, rimuoverli tutti è molto preferibile a lasciare quelli cattivi lì dentro. Grazie per il testa a testa. So che non puoi dirmi le funzionalità, ma puoi dirmi quando potresti non essere più limitato a parlare di cose di cui non puoi parlare? ;-)
Jaxidian,

Anche questo è classificato, scusa. :-)
Aaron Bertrand

Non sono sicuro di cosa intendi con il link. Quello che volevo dire è che la tua nvarchar(max)variabile raggiunge un limite dopo 4000 caratteri, 8000 caratteri se lo cambio a varchar(max). Eseguendo quello script esatto. Abbiamo ~ 450 tavoli, quindi ci colpiamo facilmente (~ 30/60 tavoli in). varchar(max)è una sintassi valida, è identica varchar(8000)e nvarchar(max)identica a nvarchar(4000).
Jaxidian,

3
Bene sì, quando si è PRINTil comando, mostra solo 8000 byte. Questa è una limitazione del PRINTcomando, non di Azure. Se esegui il comando funzionerà anche se non puoi ispezionare visivamente tutto.
Aaron Bertrand

... scusa, penso che tu abbia ragione! Grazie per avermi corretto! È quello che succede quando tua moglie si aspettava che te ne andassi 25 minuti fa ... ;-) Questa sceneggiatura funziona perfettamente per me!
Jaxidian,

6

Aggiungi una colonna nullable alla tabella, quindi rilascia la colonna. Ciò costringerà SQL a svuotare la cache per quell'oggetto.

Per quanto riguarda tutte le tabelle, un cursore dovrebbe fare il trucco. Basta usare un nome di colonna che non esisterà mai in alcuna tabella come "zzzzzz_go_away" o qualcosa del genere.


4

Il database SQL di Azure attualmente non supporta DBCC FREEPROCCACHE, quindi non è possibile rimuovere manualmente un piano di esecuzione dalla cache. Tuttavia, se si apportano modifiche a una tabella o a una vista a cui fa riferimento la query ( ALTER TABLE/ ALTER VIEW), il piano verrà rimosso dalla cache. ( Riferimento .)


Conoscevo già tutto quello che hai pubblicato qui. Questa non è né una procedura memorizzata né una vista, quindi non posso modificarne una. Come posso modificare le mie tabelle in modo insignificante, mentre sono sotto carico e senza causare tempi di inattività o blocco della tabella, per innescare questo?
Jaxidian,

1
È possibile aggiungere una colonna fittizia e quindi rilasciarla. Ciò rimuoverà il piano dalla cache. Quanto è grande il tavolo?
Kin Shah,

Questa è stata la soluzione, come raccomandato da @mrdenny. Grazie per l'aiuto!! :-)
Jaxidian,

1
Grazie ... Mancano solo pochi secondi .. Stavo rispondendo ad altri post su stackexchange ...
Kin Shah,

1

Per cancellare tutto il piano di esecuzione, utilizzare questo:

    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

Se si modifica una tabella o si visualizza facendo riferimento a essa, il piano di esecuzione viene cancellato.

Un po 'più spiegato qui http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

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.