Planen Sie die Cache-Größe und den reservierten Speicher

18

Beim Ausführen einer Abfrage mit dem tatsächlichen Ausführungsplan SELECTteilt mir der Root-Operator ( ) mit, dass die Größe des zwischengespeicherten Plans 32 KB beträgt.

Eine Abfrage , die verbindet sys.dm_exec_cached_plansund sys.dm_os_memory_objectsan dem Plan in Frage suchen, sagt , dass die Werte für pages_in_bytesund max_pages_in_bytes32768 (32 KB) sind, die die Cache - Plan Größe entspricht.

Was ich nicht verstehe ist, wofür der Wert in sys.dm_exec_cached_plans.size_in_bytes49152 (48KB) steht. Ich habe BOL in all diesen Spalten gelesen, und vor allem in size_in_bytesdenen steht:

Msgstr " Anzahl der vom Cache - Objekt verbrauchten Bytes. "

Ich kann das letzte Stück des Puzzles nicht in Ordnung bringen, um zu verstehen, was es wirklich bedeutet.

Ich weiß, dass alle Operatoren (die nicht über die zusätzliche Speichergewährung für Sortierungen und Hashes sprechen) eine bestimmte Menge an festem Speicher benötigen, um den Status zu speichern, Berechnungen durchzuführen usw., der mit dem optimierten Plan im Cache gespeichert wird, aber wo?

Meine Fragen lauten also:

  • Was heißt das size_in_byteseigentlich ?
  • Warum ist der Wert höher als "Größe des zwischengespeicherten Plans"?
  • Wo ist die feste Speicherkapazität für alle Operatoren / Iteratoren reserviert, ist sie mit der "Größe des zwischengespeicherten Plans" (32 KB in meinem Beispiel) oder woanders?

Ich weiß, dass sie verschiedene DMVs mit unterschiedlichen Funktionen sind, aber sie hängen zusammen. Die kompilierten (zwischengespeicherten) Pläne in sys.dm_exec_cached_plansJoins sys.dm_os_memory_objectsin der memory_object_addressSpalte. Der Grund, warum ich die Fragen hier poste, ist, dass ich um Hilfe frage und verstehe, wie man die DMVs und ihre Spalten interpretiert.

Wenn size_in_bytesdie Größe des zwischengespeicherten Plans ist, warum sagt SQL Server einen anderen Wert im tatsächlichen Ausführungsplan?

Neue Abfrage, neue Nummern:

  • Aktueller Plan
    • Größe des zwischengespeicherten Plans 16 KB
    • CompileMemory 96KB
  • DMVs:
    • sys.dm_exec_cached_plans.size_in_bytes 24 KB
    • sys.dm_os_memory_objects.pages_in_bytes, .max_pages_in_bytes 16 KB.

Beachten Sie außerdem, dass für diese Abfrage keine zusätzlichen Speicherzuweisungen für Sortierungen und Hash-Vorgänge erforderlich sind.

Microsoft SQL Server 2012 - 11.0.5343.0 (X64)
GordonLiddy
quelle

Antworten:

12

Der Grund dafür, dass das size_in_bytesFeld der sys.dm_exec_cached_plansDMV, zumindest in Bezug auf "Kompilierte Pläne", größer ist als das CachedPlanSizeAttribut des QueryPlanKnotens im XML-Plan, ist, dass ein kompilierter Plan nicht dasselbe ist wie ein Abfrageplan. Ein kompilierter Plan besteht aus mehreren Speicherobjekten, deren kombinierte Größe dem size_in_bytesFeld entspricht. Daher ist die in der Dokumentation angegebene Beschreibung der " Anzahl der vom Cache-Objekt verbrauchten Bytes " korrekt. es ist nur so, dass es leicht zu Fehlinterpretationen kommt, was unter "Cache-Objekt" mit dem Namen der DMV zu verstehen ist und dass der Begriff "Plan" mehrere Bedeutungen hat.

Ein kompilierte Plan ist ein Container, die verschiedenen Informationen im Zusammenhang mit der Abfrage hält Batch (also nicht nur eine einzelne Anweisung), ein (oder mehr) diese Stücke sind , um den Abfrage - Plan (s). Kompilierte Pläne haben das oberste Speicherobjekt MEMOBJ_COMPILE_ADHOC. Dies ist die Zeile sys.dm_os_memory_objects, die über das memory_object_addressFeld in beiden DMVs verknüpft ist. Dieses Speicherobjekt enthält die Symboltabelle, die Parameterauflistung, Links zu verwandten Objekten, den Accessor-Cache, den TDS-Metadaten-Cache und möglicherweise einige andere Elemente. Kompilierte Pläne werden für Sitzungen / Benutzer freigegeben, die denselben Stapel mit denselben Sitzungseinstellungen ausführen . Einige verwandte Objekte werden jedoch nicht von Sitzungen / Benutzern gemeinsam genutzt.

Kompilierte Pläne enthalten auch ein oder mehrere abhängige Objekte, die durch Übergeben des plan_handle( Eingangs sys.dm_exec_cached_plans) an den sys.dm_exec_cached_plan_dependent_objectsDMF gefunden werden können. Es gibt zwei Arten von abhängigen Objekten: Ausführbarer Plan (Speicherobjekt = MEMOBJ_EXECUTE ) und Cursor (Speicherobjekt = MEMOBJ_CURSOREXEC ). Es gibt 0 oder mehr Cursorobjekte, eines pro Cursor. Es gibt auch ein oder mehrere ausführbare Plan-Objekte, eines pro Benutzer, der denselben Stapel ausführt , daher sind ausführbare Pläne nicht vorhandenzwischen Benutzern geteilt. Ausführbare Pläne enthalten Laufzeitparameter und Informationen zu lokalen Variablen, Laufzeitstatus wie die aktuell ausgeführte Anweisung, Objekt-IDs für zur Laufzeit erstellte Objekte (ich nehme an, dies bezieht sich auf Tabellenvariablen, temporäre Tabellen, temporäre gespeicherte Prozeduren usw.). und möglicherweise andere Gegenstände.

Jede Anweisung in einem Stapel mit mehreren Anweisungen ist in einer kompilierten Anweisung enthalten (Memory Object = MEMOBJ_STATEMENT ). Die Größe jeder kompilierten Anweisung (dh pages_in_bytesgeteilt durch 1024) sollte mit den CachedPlanSize="xx"Werten der <QueryPlan>Knoten im XML-Plan übereinstimmen . Kompilierte Anweisungen haben häufig einen (möglicherweise mehrere?) Zugeordneten Laufzeit- Abfrageplan (Speicherobjekt = MEMOBJ_XSTMT ). Schließlich sollte für jeden Laufzeit-Abfrageplan, bei dem es sich um eine Abfrage handelt, ein zugehöriger Abfrageausführungskontext vorhanden sein (Speicherobjekt = MEMOBJ_QUERYEXECCNTXTFORSE ).

In Bezug auf kompilierte Anweisungen verfügen Stapel mit einzelnen Anweisungen nicht über separate kompilierte Anweisungen (dh MEMOBJ_STATEMENT ) oder separate Laufzeit- Abfrageplanobjekte (dh MEMOBJ_XSTMT ). Der Wert für jedes dieser Objekte wird im kompilierten Hauptplanobjekt (dh MEMOBJ_COMPILE_ADHOC ) gespeichert. In diesem Fall sollte der pages_in_bytesWert für dieses Hauptobjekt geteilt durch 1024 mit der CachedPlanSizeGröße im <QueryPlan>Knoten des XML-Plans übereinstimmen . Diese Werte stimmen jedoch nicht mit Batches mit mehreren Anweisungen überein.


Der size_in_bytesWert kann abgeleitet werden, indem die Einträge in der sys.dm_os_memory_objectsDMV (die oben fettgedruckten Elemente) summiert werden , die sich alle dm_os_memory_objects.page_allocator_addressauf den kompilierten Plan beziehen . Der Trick , um den richtigen Wert zu erhalten ist, zunächst die bekommen memory_object_addressvon sys.dm_exec_cached_plansfür einen bestimmten kompilierten Plan verwendet dann , dass die entsprechende bekommen MEMOBJ_COMPILE_ADHOC Reihe von sys.dm_os_memory_objectsbasierend auf seinem memory_object_addressFeld. Nehmen Sie dann den page_allocator_addressWert sys.dm_os_memory_objectsfür diese Zeile und verwenden Sie ihn, um alle Zeilen sys.dm_os_memory_objectsmit demselben page_allocator_addressWert zu erfassen . (Bitte beachten Sie, dass diese Technik für die anderen zwischengespeicherten Objekttypen nicht funktioniert: Parse Tree , Extended Proc , CLR Compiled Proc und CLR Compiled Func.)

Wenn Sie den memory_object_addressWert von verwenden sys.dm_exec_cached_plans, können Sie alle Komponenten des kompilierten Plans über die folgende Abfrage anzeigen:

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;

In der folgenden Abfrage werden alle kompilierten Pläne sys.dm_exec_cached_planszusammen mit dem Abfrageplan und den Anweisungen für jeden Stapel aufgelistet . Die Abfrage direkt darüber wird über XML als MemoryObjectsFeld in die folgende Abfrage eingefügt :

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;

Bitte beachte, dass:

  • das TotalPlanBytesFeld ist nur eine Neuaussage des sys.dm_exec_cached_plans.size_in_bytesFeldes,
  • das AllocatedBytesFeld ist die SUMME der zugehörigen Speicherobjekte, die normalerweise übereinstimmen TotalPlanBytes(dh size_in_bytes)
  • Das AllocatedBytesFeld ist gelegentlich größer als TotalPlanBytes(dh size_in_bytes), da der Speicherverbrauch während der Ausführung steigt. Dies scheint hauptsächlich auf eine Neukompilierung zurückzuführen zu sein (was anhand des angezeigten usecountsFeldes ersichtlich sein sollte 1).
  • Das BaseSingleStatementPlanKBFeld sollte mit dem CachedPlanSizeAttribut des QueryPlanKnotens in der XML übereinstimmen , jedoch nur bei Verwendung eines einzelnen Abfragestapels.
  • Bei Stapeln mit mehreren Abfragen sollten Zeilen mit der Kennzeichnung " MEMOBJ_STATEMENTin" sys.dm_os_memory_objectsfür jede Abfrage vorhanden sein. Das pages_in_bytesFeld für diese Zeilen sollte mit den einzelnen <QueryPlan>Knoten des XML-Plans übereinstimmen .

Ressourcen:

Solomon Rutzky
quelle