Il motivo per cui il size_in_bytes
campo del sys.dm_exec_cached_plans
DMV, almeno in termini di "Piani compilati", è più grande CachedPlanSize
dell'attributo del QueryPlan
nodo nel piano XML è perché un piano compilato non è la stessa cosa di un piano di query. Un piano compilato è composto da più oggetti memoria, la cui dimensione combinata corrisponde al size_in_bytes
campo. Pertanto, la descrizione di " Numero di byte consumati dall'oggetto cache " che hai trovato nella documentazione è accurata; è solo che è facile interpretare erroneamente cosa si intende per "oggetto cache" dato il nome del DMV e che il termine "piano" ha più significati.
Un piano compilato è un contenitore che contiene varie informazioni relative al batch di query (ovvero non solo una singola istruzione), uno (o più) di quei pezzi che sono i piani di query. I piani compilati hanno un oggetto memoria di livello superiore di MEMOBJ_COMPILE_ADHOC che è la riga in sys.dm_os_memory_objects
cui è collegata tramite il memory_object_address
campo in entrambi i DMV. Questo oggetto memoria contiene la tabella dei simboli, la raccolta dei parametri, i collegamenti agli oggetti correlati, la cache degli accessori, la cache dei metadati TDS e possibilmente alcuni altri elementi. I piani compilati sono condivisi tra sessioni / utenti che eseguono lo stesso batch con le stesse impostazioni di sessione. Tuttavia, alcuni oggetti correlati non sono condivisi tra Sessioni / Utenti.
I piani compilati hanno anche uno o più oggetti dipendenti che possono essere trovati passando il plan_handle
(in sys.dm_exec_cached_plans
) nel sys.dm_exec_cached_plan_dependent_objects
DMF. Esistono due tipi di oggetti dipendenti: Piano eseguibile (Oggetto memoria = MEMOBJ_EXECUTE ) e Cursore (Oggetto memoria = MEMOBJ_CURSOREXEC ). Ci saranno 0 o più oggetti cursore, uno per ogni cursore. Ci saranno anche uno o più oggetti del piano eseguibile, uno per ogni utente che esegue lo stesso batch , quindi i piani eseguibili non sonocondiviso tra utenti. I piani eseguibili contengono i parametri di runtime e le informazioni sulla variabile locale, lo stato di runtime come l'istruzione attualmente in esecuzione, gli ID oggetto per gli oggetti creati in fase di runtime (suppongo che si riferisca a variabili di tabella, tabelle temporanee, stored procedure temporanee, ecc.) e possibilmente altri elementi.
Ogni istruzione all'interno di un batch multiistruzione è contenuta in un'istruzione compilata (oggetto memoria = MEMOBJ_STATEMENT ). La dimensione di ciascuna istruzione compilata (ovvero pages_in_bytes
) divisa per 1024 dovrebbe corrispondere ai CachedPlanSize="xx"
valori dei <QueryPlan>
nodi nel piano XML. Le istruzioni compilate avranno spesso uno (forse più?) Piani di query di runtime associati (Oggetto memoria = MEMOBJ_XSTMT ). Infine, per ogni piano di query di runtime che è una query, dovrebbe essere associato un contesto di esecuzione della query (oggetto memoria = MEMOBJ_QUERYEXECCNTXTFORSE ).
Rispetto alle istruzioni compilate, i batch a istruzione singola non hanno oggetti istruzione compilata separati (ovvero MEMOBJ_STATEMENT ) o piani di query runtime separati (ovvero MEMOBJ_XSTMT ). Il valore per ciascuno di tali oggetti verrà archiviato nell'oggetto principale del piano compilato (ovvero MEMOBJ_COMPILE_ADHOC ) e, in tal caso, il pages_in_bytes
valore per quell'oggetto principale diviso per 1024 dovrebbe corrispondere alla CachedPlanSize
dimensione nel <QueryPlan>
nodo del piano XML. Tali valori non equivarranno, tuttavia, in batch multiistruzione.
Il size_in_bytes
valore può essere derivato sommando le voci nel sys.dm_os_memory_objects
DMV (gli elementi sopra indicati in grassetto), tutti correlati dm_os_memory_objects.page_allocator_address
per quel Piano compilato. Il trucco per ottenere il valore corretto è innanzitutto ottenere il memory_object_address
da sys.dm_exec_cached_plans
per un particolare piano compilato, quindi utilizzarlo per ottenere la riga MEMOBJ_COMPILE_ADHOC corrispondente in sys.dm_os_memory_objects
base al relativo memory_object_address
campo. Quindi, prendi il page_allocator_address
valore sys.dm_os_memory_objects
per quella riga e usalo per prendere tutte le righe sys.dm_os_memory_objects
che hanno lo stesso page_allocator_address
valore. (Si noti che questa tecnica non funziona con gli altri tipi di oggetti memorizzati nella cache: Parse Tree , Extended Proc , CLR Compiled Proc e CLR Compiled Func.)
Utilizzando il memory_object_address
valore ottenuto da sys.dm_exec_cached_plans
, è possibile visualizzare tutti i componenti del piano compilato tramite la seguente query:
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;
La query seguente elenca tutti i piani compilati sys.dm_exec_cached_plans
insieme al piano di query e alle dichiarazioni per ciascun batch. La query direttamente sopra è incorporata nella query seguente tramite XML come MemoryObjects
campo:
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;
Si prega di notare che:
- il
TotalPlanBytes
campo è solo una ri-dichiarazione del sys.dm_exec_cached_plans.size_in_bytes
campo,
- il
AllocatedBytes
campo è la SOMMA degli oggetti di memoria correlati che corrisponde tipicamente TotalPlanBytes
(cioè size_in_bytes
)
- il
AllocatedBytes
campo sarà occasionalmente maggiore di TotalPlanBytes
(cioè size_in_bytes
) a causa dell'aumento del consumo di memoria durante l'esecuzione. Questo sembra accadere principalmente a causa della ricompilazione (che dovrebbe essere evidente con il usecounts
campo che mostra 1
)
- il
BaseSingleStatementPlanKB
campo deve corrispondere CachedPlanSize
all'attributo del QueryPlan
nodo nell'XML, ma solo quando si utilizza un singolo batch di query.
- per i batch con più query, devono essere presenti righe contrassegnate come
MEMOBJ_STATEMENT
in sys.dm_os_memory_objects
, una per ogni query. Il pages_in_bytes
campo per queste righe deve corrispondere ai singoli <QueryPlan>
nodi del piano XML.
risorse: