Причина, по которой size_in_bytes
поле sys.dm_exec_cached_plans
DMV, по крайней мере в терминах «Скомпилированные планы», больше, чем CachedPlanSize
атрибут QueryPlan
узла в плане XML, заключается в том, что скомпилированный план - это не то же самое, что план запроса. Скомпилированный план состоит из нескольких объектов памяти, общий размер которых равен size_in_bytes
полю. Итак, описание « Количество байтов, использованных объектом кэша », которое вы нашли в документации, является точным; это просто, что легко неверно истолковать, что подразумевается под «объектом кэша», заданным именем DMV, и что термин «план» имеет несколько значений.
Скомпилированный план представляет собой контейнер , который содержит различные элементы информации , связанные с запросом пакета (то есть не только одно заявление), один (или более) из этих частей , являющихся план запроса (ов). Скомпилированные планы имеют объект памяти верхнего уровня MEMOBJ_COMPILE_ADHOC, который является строкой sys.dm_os_memory_objects
, связанной через memory_object_address
поле в обоих DMV. Этот объект памяти содержит таблицу символов, набор параметров, ссылки на связанные объекты, кэш доступа, кэш метаданных TDS и, возможно, некоторые другие элементы. Скомпилированные планы распределяются между сеансами / пользователями, которые выполняют один и тот же пакет с одинаковыми настройками сеанса. Однако некоторые связанные объекты не являются общими для сеансов / пользователей.
Скомпилированные планы также имеют один или несколько зависимых объектов, которые можно найти, передав plan_handle
(в sys.dm_exec_cached_plans
) в sys.dm_exec_cached_plan_dependent_objects
DMF. Существует два типа зависимых объектов: исполняемый план (объект памяти = MEMOBJ_EXECUTE ) и курсор (объект памяти = MEMOBJ_CURSOREXEC ). Там будет 0 или более объектов Cursor, по одному на каждый курсор. Также будет один или несколько объектов исполняемого плана, по одному на каждого пользователя, выполняющего тот же пакет , следовательно, исполняемые планы не являютсяделится между пользователями. Исполняемые планы содержат параметр времени выполнения и информацию о локальной переменной, состояние времени выполнения, такое как текущий выполняемый оператор, идентификаторы объектов для объектов, созданных во время выполнения (я предполагаю, что это относится к переменным таблиц, временным таблицам, временным хранимым процедурам и т. Д.) и, возможно, другие предметы.
Каждый оператор в пакете с несколькими операторами содержится в скомпилированном операторе (объект памяти = MEMOBJ_STATEMENT ). Размер каждого скомпилированного pages_in_bytes
оператора (т. Е. ), Деленный на 1024, должен соответствовать CachedPlanSize="xx"
значениям <QueryPlan>
узлов в плане XML. Скомпилированные операторы часто имеют один (возможно, более?) Связанный план выполнения во время выполнения (объект памяти = MEMOBJ_XSTMT ). Наконец, для каждого плана выполнения во время выполнения, который является запросом, должен быть связанный контекст выполнения запроса (объект памяти = MEMOBJ_QUERYEXECCNTXTFORSE ).
Что касается скомпилированных операторов, то пакеты с одним оператором не имеют отдельных объектов скомпилированного оператора (например, MEMOBJ_STATEMENT ) или отдельного плана выполнения (например, MEMOBJ_XSTMT ). Значение для каждого из этих объектов будет храниться в основном объекте скомпилированного плана (т.е. MEMOBJ_COMPILE_ADHOC ), и в этом случае pages_in_bytes
значение этого основного объекта, деленное на 1024, должно соответствовать CachedPlanSize
размеру в <QueryPlan>
узле плана XML. Однако эти значения не будут равны в пакетах с несколькими утверждениями.
size_in_bytes
Значение может быть получено путем суммирования записей в sys.dm_os_memory_objects
DMV (пункты отмечено выше жирным шрифтом), все связаны dm_os_memory_objects.page_allocator_address
для этого Составитель плана. Хитрость , чтобы получить правильное значение является первым получить memory_object_address
от sys.dm_exec_cached_plans
для конкретного Составитель плана, а затем использовать это , чтобы получить соответствующую MEMOBJ_COMPILE_ADHOC строку из sys.dm_os_memory_objects
основываясь на своем memory_object_address
поле. Затем возьмите page_allocator_address
значение sys.dm_os_memory_objects
для этой строки и используйте его, чтобы получить все строки с sys.dm_os_memory_objects
одинаковым page_allocator_address
значением. (Пожалуйста , обратите внимание , что этот метод не работает для других кэшированных типов объектов: дерево разбора , Extended Proc , CLR Составитель Proc и CLR Составитель Func.)
Используя memory_object_address
значение, полученное из sys.dm_exec_cached_plans
, вы можете увидеть все компоненты скомпилированного плана с помощью следующего запроса:
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;
В приведенном ниже запросе перечислены все скомпилированные планы sys.dm_exec_cached_plans
вместе с планом запроса и инструкциями для каждого пакета. Запрос непосредственно выше включен в запрос ниже через XML как MemoryObjects
поле:
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;
Обратите внимание, что:
TotalPlanBytes
поле просто повторно заявление sys.dm_exec_cached_plans.size_in_bytes
поля,
AllocatedBytes
поле является суммой соответствующих объектов памяти , которые обычно матчей TotalPlanBytes
(т.е. size_in_bytes
)
AllocatedBytes
поле иногда будет больше TotalPlanBytes
(то есть size_in_bytes
) в связи с потреблением памяти увеличивающегося во время выполнения. Похоже, что это происходит в основном из-за перекомпиляции (что должно быть видно при usecounts
отображении поля 1
)
BaseSingleStatementPlanKB
поле должно соответствовать CachedPlanSize
атрибут QueryPlan
узла в XML, но только при использовании одной партии запроса.
- для партий с несколькими запросами, должны быть помечены как строки
MEMOBJ_STATEMENT
в sys.dm_os_memory_objects
, по одному для каждого запроса. pages_in_bytes
Поле для этих строк должны соответствовать отдельным <QueryPlan>
узлам плана XML.
Ресурсы: