DMV 的size_in_bytes
字段sys.dm_exec_cached_plans
至少在“已编译计划”方面大于XML计划中节点的CachedPlanSize
属性的QueryPlan
原因是因为已编译计划与查询计划不同。编译计划由多个内存对象组成,这些对象的总大小等于该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对象,每个光标一个。也将有一个或多个可执行计划对象,每个执行同一批次的每个用户一个,因此,可执行计划不是用户之间共享。可执行计划包含运行时参数和局部变量信息,运行时状态(例如当前正在执行的语句),在运行时创建的对象的对象ID(我假定这是指表变量,临时表,临时存储过程等) ,以及其他可能的项目。
多语句批处理中的每个语句都包含在已编译语句中(内存对象= MEMOBJ_STATEMENT)。每个已编译语句(即pages_in_bytes
)的大小除以1024,应与XML计划中节点的CachedPlanSize="xx"
值匹配<QueryPlan>
。编译后的语句通常会有一个(可能还有更多)关联的运行时查询计划(Memory Object = MEMOBJ_XSTMT)。最后,对于作为查询的每个运行时查询计划,应该有一个关联的查询执行上下文(内存对象= MEMOBJ_QUERYEXECCNTXTFORSE)。
关于编译语句,单语句批没有单独的编译语句(即MEMOBJ_STATEMENT)或单独的运行时查询计划(即MEMOBJ_XSTMT)对象。这些对象中每个对象的值都将存储在主编译计划对象(即MEMOBJ_COMPILE_ADHOC)中,在这种情况下,该pages_in_bytes
主对象的值除以1024应该与XML计划节点中的CachedPlanSize
大小匹配<QueryPlan>
。但是,在多语句批处理中,这些值将不相等。
该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行。然后,从该行中获取值,并使用它从该行中获取具有相同值的所有行。(请注意,该技术不适用于其他缓存对象类型:语法分析树,扩展的Proc,CLR编译的Proc和CLR编译的功能sys.dm_os_memory_objects
memory_object_address
page_allocator_address
sys.dm_os_memory_objects
sys.dm_os_memory_objects
page_allocator_address
)
使用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
字段应与XML中节点的CachedPlanSize
属性匹配QueryPlan
,但仅在使用单个查询批处理时才应匹配。
- 对于具有多个查询的批次,应在中标记为
MEMOBJ_STATEMENT
中的行sys.dm_os_memory_objects
,每个查询一行。pages_in_bytes
这些行的字段应与<QueryPlan>
XML计划的各个节点匹配。
资源: