Jak mogę usunąć zły plan wykonania z bazy danych Azure SQL?

12

DBCC FREEPROCCACHEnie działa w usłudze Azure SQL DB. Jak inaczej zmusić plan wyrzucenia się z pamięci podręcznej w sposób, który nie zaszkodzi systemowi produkcyjnemu (tzn. Nie mogę po prostu zmieniać tabel, chcąc nie chcąc)? Jest to specjalnie dla SQL utworzonego przez Entity Framework, więc nie są to samodzielnie zarządzane przechowywane procy - to efektywnie dynamiczny SQL.

(Źródłem były złe indeksy -> złe statystyki itp. To wszystko zostało naprawione, ale zły plan nie zniknie.)

AKTUALIZACJA: Wybrałem rozwiązanie @ mrdenny, gdy dotarł tam pierwszy. Jednak z powodzeniem używam skryptu @Aaron Bertrand do wykonywania pracy. Dziękuję wszystkim za pomoc !!

Jaxidian
źródło
Czy możesz wykonać sp_recompile na platformie Azure?
mrdenny,
Tak. Na czym dokładnie bym go uruchomił? Nie mamy zapisanych proc. To jest dynamiczny SQL uruchomiony sp_executesql.
Jaxidian
2
Możesz uruchomić go na stole samodzielnie, co powinno opróżnić plany korzystające z tego stołu. (Jeśli to
zadziała, dam
1
Właśnie próbowałem tego na stole i najwyraźniej blokuje on stół w transakcji podczas przetwarzania. Wypróbowałem to na 10-kolumnowym stole z tylko 24 rekordami i zajęło mi to minutę. W tym czasie nie mogłem przesłać zapytania do tabeli. Nie mogę uruchomić czegoś takiego na naszych prawdziwych stołach w Production!
Jaxidian
1
Cholera, to kłótnia. Wygląda na to, że musisz wprowadzić zmianę schematu, np. Dodać kolumnę zerowalną, a następnie upuścić. To również wyczyści pamięć podręczną i powinno być szybkie. Testowanie na pewno powie.
mrdenny,

Odpowiedzi:

12

Azure SQL teraz bezpośrednio to obsługuje

Baza danych Azure SQL bezpośrednio obsługuje czyszczenie pamięci podręcznej proc bieżącej bazy danych użytkownika bez żadnych włamań:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

Dodatkowe informacje

Poniższy skrypt ( Shannon Gowen ) może być używany do oglądania procesu krok po kroku:

-- 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
źródło
Nie próbowałem tego jeszcze, ale jeśli jest to faktycznie funkcjonalne, to prawdopodobnie jest to „najlepsza” odpowiedź na początku 2017 r. Dzięki za to - nie miałem pojęcia, że ​​to tam było! :-)
Jaxidian
Próbowałem tego (na Premium DB) i zadziałało.
Remi Lemarchand
Oflagowałem to jako zaktualizowaną „Zaakceptowaną odpowiedź”, ale jeszcze tego nie przetestowałem. Opieram to bezpośrednio na opiniach Todda i Remi. Dziękuje wszystkim!
Jaxidian
Jeszcze raz odwiedziłem, skorzystałem z tego i działało to dla mnie dobrze! Dodam kilka dodatkowych skryptów do odpowiedzi Todda, aby ją wzbogacić, ale jego post trafił w sedno.
Jaxidian
Wydaje mi się, że to nie działa - po prostu wykonuje się, ale listy są nadal pełne - Jestem na SQL Azure - co może być nie tak?
Dirk Boer
12

Nie ma dziś na to jednoznacznego sposobu, ale nie jest to stały scenariusz (komenda DBCC nadal nie jest obsługiwana, ale czytana w magazynie zapytań ). Nawet jeśli trafienie zmiany schematu jest dopuszczalne, może nie być tym, czego chcesz, ponieważ spowoduje to unieważnienie wszystkich planów związanych z obiektem bazowym, nie tylko złym.

Nie szukanie uznania za to, ale budowanie dynamicznego SQL w celu wykonania tej samej operacji na wielu tabelach jest dość łatwe:

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;

(Napisałem wskazówkę dotyczącą tego problemu dotyczącego „długości dynamicznego SQL” ...)

Aaron Bertrand
źródło
W moim przypadku usunięcie ich wszystkich jest o wiele lepsze niż pozostawienie złych. Dzięki za heads-upy. Wiem, że nie możesz mi powiedzieć o funkcjach, ale czy możesz mi powiedzieć, kiedy możesz już nie być ograniczony do mówienia o rzeczach, o których nie możesz rozmawiać? ;-)
Jaxidian
To również jest tajne, przepraszam. :-)
Aaron Bertrand
Nie jestem pewien, co rozumiesz przez link. Chodziło mi o to, że twoja nvarchar(max)zmienna osiąga limit po 4000 znaków, 8000 znaków, jeśli zmienię na varchar(max). Uruchamianie dokładnie tego skryptu. Mamy ~ 450 tabel, więc łatwo to trafiliśmy (~ 30/60 tabel w). varchar(max)jest poprawną składnią, jest po prostu identyczna varchar(8000)i nvarchar(max)identyczna z nvarchar(4000).
Jaxidian
3
Cóż, tak, kiedy to PRINTpolecenie wyświetla tylko 8000 bajtów. To ograniczenie PRINTpolecenia, a nie Azure. Jeśli uruchomisz polecenie, będzie działać, nawet jeśli nie możesz wizualnie sprawdzić całości.
Aaron Bertrand
... doh, przepraszam, myślę, że masz rację! Dzięki za poprawienie mnie! Tak się dzieje, kiedy Twoja żona spodziewała się, że odejdziesz 25 minut temu ... ;-) Ten skrypt działa dla mnie idealnie!
Jaxidian
6

Dodaj kolumnę zerowalną do tabeli, a następnie upuść kolumnę. Zmusi to SQL do opróżnienia pamięci podręcznej dla tego obiektu.

Jeśli chodzi o wykonanie wszystkich tabel, kursor powinien załatwić sprawę. Wystarczy użyć nazwy kolumny, która nigdy nie będzie istnieć w żadnej tabeli, takiej jak „zzzzzz_go_away” lub coś w tym rodzaju.

mrdenny
źródło
4

Baza danych Azure SQL obecnie nie obsługuje DBCC FREEPROCCACHE, więc nie można ręcznie usunąć planu wykonania z pamięci podręcznej. Jeśli jednak wprowadzisz zmiany w tabeli lub widoku, do którego odwołuje się zapytanie ( ALTER TABLE/ ALTER VIEW), plan zostanie usunięty z pamięci podręcznej. ( Odnośnik .)

Kin Shah
źródło
Wiedziałem już wszystko, co tu opublikowałeś. To nie jest procedura przechowywana ani widok, więc nie mogę modyfikować żadnej z nich. Jak mogę zmodyfikować swoje tabele w nieistotny sposób, pod obciążeniem i bez powodowania jakichkolwiek przestojów lub blokowania stołu, aby to uruchomić?
Jaxidian
1
Możesz ewentualnie dodać fikcyjną kolumnę, a następnie upuścić ją. Spowoduje to usunięcie planu z pamięci podręcznej. Jak duży jest stół?
Kin Shah,
Skończyło się to rozwiązaniem, zgodnie z zaleceniami @mrdenny. Dzięki za pomoc!! :-)
Jaxidian
1
Dzięki ... Zaledwie kilka sekund w krótkim czasie .. Odpowiadałem na inny post na stackexchange ...
Kin Shah
1

Aby wyczyścić cały plan wykonania, użyj tego:

    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

W przypadku zmiany tabeli lub widoku do niej odwołującego się plan wykonania zostanie wyczyszczony.

Trochę więcej wyjaśniono tutaj http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

chrześcijanin
źródło