Zaplanuj rozmiar pamięci podręcznej i zarezerwowaną pamięć

18

Podczas uruchamiania zapytania zawierającego rzeczywisty plan wykonania operator root ( SELECT) informuje mnie, że rozmiar planu buforowanego wynosi 32 KB.

Zapytanie, które łączy się sys.dm_exec_cached_plansi sys.dm_os_memory_objectspatrząc na dany plan, mówi, że wartości dla pages_in_bytesi max_pages_in_byteswynoszą 32768 (32 KB), co odpowiada rozmiarowi buforowanego planu.

Nie rozumiem tylko, co oznacza wartość sys.dm_exec_cached_plans.size_in_bytes, czyli 49152 (48 KB). Przeczytałem BOL we wszystkich tych kolumnach, a zwłaszcza z tym, size_in_bytesco mówi:

Liczba bajtów zajętych przez obiekt pamięci podręcznej.

Nie mogę umieścić ostatniego kawałka układanki, aby zrozumieć, co to naprawdę znaczy.

Wiem, że wszyscy operatorzy (nie mówiąc o dodatkowym przydziale pamięci używanym do sortowania i skrótów) wymagają pewnej ilości stałej pamięci, do przechowywania stanu, wykonywania obliczeń itp., Która jest przechowywana ze zoptymalizowanym planem w pamięci podręcznej, ale gdzie?

Tak więc moje pytania to:

  • Co to size_in_bytesnaprawdę znaczy?
  • Dlaczego jest to wyższa wartość niż „Rozmiar planu buforowanego”?
  • Gdzie jest zarezerwowana stała ilość pamięci dla wszystkich operatorów / iteratorów, czy jest to z „rozmiarem planu buforowanego” (32 KB w moim przykładzie), czy gdziekolwiek indziej?

Wiem, że to różne DMV z różnymi funkcjami, ale są ze sobą powiązane. Skompilowane (buforowane) plany sys.dm_exec_cached_planspołączeń sys.dm_os_memory_objectsw memory_object_addresskolumnie. Powodem, dla którego tutaj zamieszczam pytania, jest to, że proszę o pomoc w zrozumieniu, jak interpretować DMV i ich kolumny.

Jeśli size_in_bytesjest rozmiar planu buforowanego, dlaczego SQL Server mówi inną wartość w rzeczywistym planie wykonania?

Nowe zapytanie, nowe numery:

  • Rzeczywisty plan
    • Rozmiar planu buforowanego 16 KB
    • CompileMemory 96KB
  • DMV:
    • sys.dm_exec_cached_plans.size_in_bytes 24 KB
    • sys.dm_os_memory_objects.pages_in_bytes, .max_pages_in_bytes 16 KB.

Należy również pamiętać, że to zapytanie nie wymaga żadnych dodatkowych przydziałów pamięci dla operacji sortowania i mieszania.

Microsoft SQL Server 2012 - 11.0.5343.0 (X64)
GordonLiddy
źródło

Odpowiedzi:

12

Powodem, dla którego size_in_bytespole sys.dm_exec_cached_plansDMV, przynajmniej w kategoriach „planów skompilowanych”, jest większe niż CachedPlanSizeatrybut QueryPlanwę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_bytespolu. 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_objectspołączonym przez memory_object_addresspole 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_objectsDMF. 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 niewspół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_byteswartość tego głównego obiektu podzielona przez 1024 powinna być zgodna z CachedPlanSizerozmiarem w <QueryPlan>węźle planu XML. Wartości te nie będą jednak równe w partiach zawierających wiele instrukcji.


size_in_bytesWartość można uzyskać poprzez zsumowanie wpisy w sys.dm_os_memory_objectsDMV (pozycje wspomniano powyżej pogrubione), przez wszystkie związane dm_os_memory_objects.page_allocator_addressz tym skompilowany planu. Sposób na uzyskanie poprawnej wartości polega na tym, aby najpierw uzyskać memory_object_addressod sys.dm_exec_cached_plansokreś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_addresspola. Następnie pobierz page_allocator_addresswartość z sys.dm_os_memory_objectstego wiersza i użyj go, aby pobrać wszystkie wiersze sys.dm_os_memory_objectso tej samej page_allocator_addresswartoś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_addresswartość 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_planswraz z planem zapytań i instrukcjami dla każdej partii. Zapytanie bezpośrednio powyżej jest włączone do zapytania poniżej poprzez XML jako MemoryObjectspole:

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ć:

  • TotalPlanBytespole jest tylko ponowne oświadczenie o sys.dm_exec_cached_plans.size_in_byteszakresie,
  • AllocatedBytespole jest sumą powiązanych obiektów pamięci, które zwykle jest dopasowany TotalPlanBytes(tj size_in_bytes)
  • AllocatedBytespole 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 usecountspolu pokazującym 1)
  • BaseSingleStatementPlanKBpola powinny pasować do CachedPlanSizeatrybutu QueryPlanwęzła w XML, ale tylko przy użyciu pojedynczej partii zapytania.
  • dla partii z wieloma zapytaniami powinny być zaznaczone wiersze jako MEMOBJ_STATEMENTin sys.dm_os_memory_objects, po jednym dla każdego zapytania. pages_in_bytesPole dla tych wierszach powinny odpowiadać poszczególne<QueryPlan> węzły planu XML.

Zasoby:

Solomon Rutzky
źródło