Powodem, dla którego size_in_bytes
pole sys.dm_exec_cached_plans
DMV, przynajmniej w kategoriach „planów skompilowanych”, jest większe niż CachedPlanSize
atrybut QueryPlan
węzła w planie XML, jest to, że plan skompilowany nie jest tym samym, co plan zapytań. Skompilowany plan składa się z wielu obiektów pamięci, których łączny rozmiar odpowiada size_in_bytes
polu. Tak więc opis „ liczby bajtów zajętych przez obiekt pamięci podręcznej ” znaleziony w dokumentacji jest dokładny; po prostu łatwo jest źle zinterpretować znaczenie „obiektu pamięci podręcznej”, biorąc pod uwagę nazwę DMV, i że termin „plan” ma wiele znaczeń.
Plan skompilowany jest kontenerem, który przechowuje różne informacje związane z partią zapytań (tj. Nie tylko pojedynczą instrukcję), przy czym jeden (lub więcej) z tych fragmentów jest planem (planami) zapytania. Skompilowane plany zawierają obiekt pamięci najwyższego poziomu MEMOBJ_COMPILE_ADHOC, który jest wierszem sys.dm_os_memory_objects
połączonym przez memory_object_address
pole w obu DMV. Ten obiekt pamięci zawiera tablicę symboli, kolekcję parametrów, łącza do powiązanych obiektów, pamięć podręczną akcesorium, pamięć podręczną metadanych TDS i ewentualnie inne elementy. Skompilowane plany są udostępniane między sesjami / użytkownikami, którzy wykonują tę samą partię z tymi samymi ustawieniami sesji. Jednak niektóre powiązane obiekty nie są udostępniane między sesjami / użytkownikami.
Plany skompilowane zawierają również jeden lub więcej zależnych obiektów, które można znaleźć, przekazując plan_handle
(in sys.dm_exec_cached_plans
) do sys.dm_exec_cached_plan_dependent_objects
DMF. Istnieją dwa typy obiektów zależnych: Plan wykonywalny (Obiekt pamięci = MEMOBJ_EXECUTE ) i Kursor (Obiekt pamięci = MEMOBJ_CURSOREXEC ). Będzie 0 lub więcej obiektów Kursorów, po jednym na każdy kursor. Będzie także jeden lub więcej obiektów Planu wykonywalnego, po jednym dla każdego użytkownika wykonującego tę samą partię , dlatego Plany wykonywalne nie sąwspółdzielone między użytkownikami. Plany wykonywalne zawierają parametry wykonawcze i informacje o zmiennych lokalnych, stan wykonawczy, taki jak aktualnie wykonywana instrukcja, identyfikatory obiektów dla obiektów utworzonych w czasie wykonywania (zakładam, że odnosi się to do zmiennych tabel, tabel tymczasowych, tymczasowych procedur przechowywanych itp.) i ewentualnie inne przedmioty.
Każda instrukcja w partii zawierającej wiele instrukcji jest zawarta w instrukcji skompilowanej (Obiekt pamięci = MEMOBJ_STATEMENT ). Rozmiar każdej instrukcji skompilowanej (tj. pages_in_bytes
) Podzielonej przez 1024 powinien być zgodny z CachedPlanSize="xx"
wartościami <QueryPlan>
węzłów w planie XML. Skompilowane instrukcje często mają jeden (prawdopodobnie więcej?) Powiązany plan zapytań środowiska wykonawczego (Obiekt pamięci = MEMOBJ_XSTMT ). Wreszcie dla każdego planu zapytań środowiska wykonawczego, który jest zapytaniem, powinien istnieć powiązany kontekst wykonywania zapytania (Obiekt pamięci = MEMOBJ_QUERYEXECCNTXTFORSE ).
W odniesieniu do instrukcji skompilowanych, partie pojedynczych instrukcji nie mają osobnych instrukcji skompilowanych (tj. MEMOBJ_STATEMENT ) ani oddzielnych obiektów planu zapytań środowiska wykonawczego (tj. MEMOBJ_XSTMT ). Wartość każdego z tych obiektów będzie przechowywana w głównym obiekcie Planu Kompilowanego (tj. MEMOBJ_COMPILE_ADHOC ), w takim przypadku pages_in_bytes
wartość tego głównego obiektu podzielona przez 1024 powinna być zgodna z CachedPlanSize
rozmiarem w <QueryPlan>
węźle planu XML. Wartości te nie będą jednak równe w partiach zawierających wiele instrukcji.
size_in_bytes
Wartość można uzyskać poprzez zsumowanie wpisy w sys.dm_os_memory_objects
DMV (pozycje wspomniano powyżej pogrubione), przez wszystkie związane dm_os_memory_objects.page_allocator_address
z tym skompilowany planu. Sposób na uzyskanie poprawnej wartości polega na tym, aby najpierw uzyskać memory_object_address
od sys.dm_exec_cached_plans
określonego Planu Skompilowanego, a następnie użyć go, aby uzyskać odpowiedni wiersz MEMOBJ_COMPILE_ADHOCsys.dm_os_memory_objects
na podstawie jego memory_object_address
pola. Następnie pobierz page_allocator_address
wartość z sys.dm_os_memory_objects
tego wiersza i użyj go, aby pobrać wszystkie wiersze sys.dm_os_memory_objects
o tej samej page_allocator_address
wartości. (Należy pamiętać, że ta technika nie działa w przypadku innych typów obiektów buforowanych: parsowania drzewa , rozszerzonego przetwarzania , skompilowanego przetwarzania CLR i obsługiwanego działania CLR.)
Wykorzystując memory_object_address
wartość uzyskaną zsys.dm_exec_cached_plans
, możesz zobaczyć wszystkie składniki Planu Kompilowanego za pomocą następującego zapytania:
DECLARE @CompiledPlanAddress VARBINARY(8) = 0x00000001DC4A4060;
SELECT obj.memory_object_address, obj.pages_in_bytes, obj.type
FROM sys.dm_os_memory_objects obj
WHERE obj.page_allocator_address = (
SELECT planobj.page_allocator_address
FROM sys.dm_os_memory_objects planobj
WHERE planobj.memory_object_address = @CompiledPlanAddress
)
ORDER BY obj.[type], obj.pages_in_bytes;
Poniższe zapytanie zawiera listę wszystkich skompilowanych planów sys.dm_exec_cached_plans
wraz z planem zapytań i instrukcjami dla każdej partii. Zapytanie bezpośrednio powyżej jest włączone do zapytania poniżej poprzez XML jako MemoryObjects
pole:
SELECT cplan.bucketid,
cplan.pool_id,
cplan.refcounts,
cplan.usecounts,
cplan.size_in_bytes,
cplan.memory_object_address,
cplan.cacheobjtype,
cplan.objtype,
cplan.plan_handle,
'---' AS [---],
qrypln.[query_plan],
sqltxt.[text],
'---' AS [---],
planobj.pages_in_bytes,
planobj.pages_in_bytes / 1024 AS [BaseSingleStatementPlanKB],
'===' AS [===],
cplan.size_in_bytes AS [TotalPlanBytes],
bytes.AllocatedBytes,
(SELECT CONVERT(VARCHAR(30), obj.memory_object_address, 1)
AS [memory_object_address], obj.pages_in_bytes, obj.[type]
--,obj.page_size_in_bytes
FROM sys.dm_os_memory_objects obj
WHERE obj.page_allocator_address = planobj.page_allocator_address
FOR XML RAW(N'object'), ROOT(N'memory_objects'), TYPE) AS [MemoryObjects]
FROM sys.dm_exec_cached_plans cplan
OUTER APPLY sys.dm_exec_sql_text(cplan.[plan_handle]) sqltxt
OUTER APPLY sys.dm_exec_query_plan(cplan.[plan_handle]) qrypln
INNER JOIN sys.dm_os_memory_objects planobj
ON planobj.memory_object_address = cplan.memory_object_address
OUTER APPLY (SELECT SUM(domo.[pages_in_bytes]) AS [AllocatedBytes]
FROM sys.dm_os_memory_objects domo
WHERE domo.page_allocator_address = planobj.page_allocator_address) bytes
WHERE cplan.parent_plan_handle IS NULL
AND cplan.cacheobjtype IN (N'Compiled Plan', N'Compiled Plan Stub')
--AND cplan.plan_handle = 0x06000D0031CD572910529CE001000000xxxxxxxx
ORDER BY cplan.objtype, cplan.plan_handle;
Proszę to zanotować:
TotalPlanBytes
pole jest tylko ponowne oświadczenie o sys.dm_exec_cached_plans.size_in_bytes
zakresie,
AllocatedBytes
pole jest sumą powiązanych obiektów pamięci, które zwykle jest dopasowany TotalPlanBytes
(tj size_in_bytes
)
AllocatedBytes
pole będzie od czasu do czasu być większa niż TotalPlanBytes
(tjsize_in_bytes
) w wyniku zużycia pamięci rośnie w realizacji. Wydaje się, że dzieje się tak głównie z powodu ponownej kompilacji (co powinno być widoczne w usecounts
polu pokazującym 1
)
BaseSingleStatementPlanKB
pola powinny pasować do CachedPlanSize
atrybutu QueryPlan
węzła w XML, ale tylko przy użyciu pojedynczej partii zapytania.
- dla partii z wieloma zapytaniami powinny być zaznaczone wiersze jako
MEMOBJ_STATEMENT
in sys.dm_os_memory_objects
, po jednym dla każdego zapytania. pages_in_bytes
Pole dla tych wierszach powinny odpowiadać poszczególne<QueryPlan>
węzły planu XML.
Zasoby: