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


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;

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” ...)


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.


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 .)


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/

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.