Jak usunąć określony zły plan z pamięci podręcznej zapytań programu SQL Server?

33

Mamy jedno konkretne zapytanie SQL Server 2008 (nie zapisany proc, ale ten sam ciąg SQL - wykonywany co 5 minut), który sporadycznie buforuje bardzo zły plan zapytań.

To zapytanie zwykle działa w ciągu kilku milisekund, ale przy tym złym planie zapytań zajmuje to ponad 30 sekund.

Jak chirurgicznie usunąć tylko jeden zły plan zapytań z pamięci podręcznej z programu SQL Server 2008, nie usuwając całej pamięci podręcznej zapytań na produkcyjnym serwerze bazy danych?

Jeff Atwood
źródło

Odpowiedzi:

39

Wymyśliłem kilka rzeczy

select * from sys.dm_exec_query_stats

pokaże wszystkie buforowane plany zapytań. Niestety nie jest tam wyświetlany tekst SQL.

Możesz jednak dołączyć tekst SQL do planów w następujący sposób:

select plan_handle, creation_time, last_execution_time, execution_count, qt.text
FROM 
   sys.dm_exec_query_stats qs
   CROSS APPLY sys.dm_exec_sql_text (qs.[sql_handle]) AS qt

Odtąd dodawanie WHEREklauzuli w celu znalezienia SQL, o którym wiem, że jest w zapytaniu, jest dość proste , a następnie mogę wykonać:

DBCC FREEPROCCACHE (plan_handle_id_goes_here)

aby usunąć każdy plan zapytań z pamięci podręcznej planu zapytań. Nie do końca łatwe lub wygodne, ale wydaje się działać.

edycja: zrzut całej pamięci podręcznej zapytania również będzie działał i jest mniej niebezpieczny niż się wydaje, przynajmniej z mojego doświadczenia:

DBCC FREESYSTEMCACHE ('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
Jeff Atwood
źródło
2
porady dotyczące korzystania ze wskazówki dotyczącej planu są jednak ważne.
Remus Rusanu,
1
Znalazłem to po moim magicznym odświeżeniu zapytania, to zły plan, ale planuję przetestować go następnym razem. Wskazówka dotycząca planu nie pomaga, jeśli kwerenda cierpi na „opcjonalne-itis” - gdzie ma wiele opcjonalnych parametrów i została zoptymalizowana dla jednego zestawu, a następnie uruchomiona dla innego zestawu. Nie ma optymalnego planu, który można dołączyć do tego rodzaju zapytań. Istnieje optymalny plan dla jednego zestawu parametrów, który z kolei jest okropny dla innego zestawu parametrów.
Nick.McDermaid
6

Jeśli wiesz, jak wygląda dobry plan, skorzystaj z podpowiedzi .

Nie można usunąć określonego wpisu pamięci podręcznej, ale można wyczyścić całą pulę pamięci podręcznej DBCC FREESYSTEMCACHE(cachename/poolname).

Możesz uzyskać nazwę pamięci podręcznej złego planu zapytań, jeśli masz uchwyt planu (z sys.dm_exec_requests.plan_handle dla id_sesji w kłopocie podczas wykonywania lub z sys.dm_exec_query_stats po wykonaniu):

select ce.name
from sys.dm_exec_cached_plans cp
join sys.dm_os_memory_cache_entries ce on cp.memory_object_address = ce.memory_object_address
where cp.plan_handle = @bad_plan

Jednak wszystkie plany SQL mają nazwę „Plany SQL”, co sprawia, że ​​wybranie odpowiedniego dla DBCC FREESYSTEMCACHE jest ... trudnym wyborem.

Aktualizacja

Nieważne, zapomniałem DBCC FREEPROCCACHE(plan_handle), tak, to zadziała.

Remus Rusanu
źródło
1
Możliwość przekazania uchwytu_planu do DBCC FREEPROCCACHE jest dostępna w SQL Server 2008, a nie w SQL Server 2005.
Mario
Co to znaczy, że sys.dm_exec_cached_plansnie ma w nim wpisu dla plan_handleod sys.dm_exec_requests?
Jonathan Gilbert
@JonathanGilbert oznacza, że ​​plan nie był buforowany lub został eksmitowany z pamięci podręcznej. Zobacz docs.microsoft.com/en-us/sql/relational-databases/…
Remus Rusanu
Tak więc, aby potwierdzić, mimo że dopiero zacząłem uruchamiać to zapytanie , a zapytanie nie ma żadnej wzmianki o tym, żeby go nie buforować, można je usunąć, ponieważ SQL Server podjął decyzję o wartości, aby nie buforować? Nie byłoby tak, ponieważ wciąż działa, prawda? Jeśli zdecyduje się buforować plan, to będzie buforowany od momentu, w którym zapytanie zacznie działać?
Jonathan Gilbert
1

Rozwiązanie FREEPROCCACHE jest w porządku, ale bardziej bezpośrednim sposobem na to jest użycie OPCJI (RECOMPILE) na swoim ciągu SQL (wspomniałeś, że to nie był SP), to mówi silnikowi, że jest to plan jednorazowego użytku, ponieważ prawdopodobnie podejrzewasz istnieje wąchanie parametrów lub statystyki są drastycznie różne w różnych biegach i podejrzewasz, że jest to problem z błędnym planem buforowanym.

DECLARE @SQL NVARCHAR(4000)
SELECT @SQL = 'SELECT * FROM Table WHERE Column LIKE @NAME OPTION (RECOMPILE)'
EXEC sp_executesql @SQL, N'@NAME varchar(15)', 'MyName' 
CodeCowboyOrg
źródło