计划缓存大小和保留内存


18

当运行包括实际执行计划在内的查询时,根运算符(SELECT)告诉我缓存计划大小为32KB。

该连接的查询sys.dm_exec_cached_planssys.dm_os_memory_objects,看问题的计划,称该值pages_in_bytesmax_pages_in_bytes为32768(32KB),它匹配缓存计划的大小。

我不明白的是sys.dm_exec_cached_plans.size_in_bytes49152(48KB)中的值代表什么。我已经在所有这些专栏中阅读了BOL,尤其是size_in_bytes这样说:

缓存对象消耗的字节数。

我无法理解难题的最后一部分,以了解其真正含义。

我知道所有运算符(不是在谈论用于排序和散列的额外内存授予)都需要一定数量的固定内存来存储状态,进行计算等,这些内存与优化后的计划一起存储在缓存中,但是在哪里?

因此,我的问题是:

  • 到底是size_in_bytes什么意思
  • 为什么它的值比“缓存的计划大小”高?
  • 为所有操作员/迭代器保留的固定内存量是哪里,是使用“缓存的计划大小”(在我的示例中为32Kb)还是其他任何地方?

我知道它们是具有不同功能的不同DMV,但它们是相关的。在编译(缓存)计划sys.dm_exec_cached_plans加入sys.dm_os_memory_objectsmemory_object_address列。我在此处发布问题的原因是,我正在寻求帮助,了解如何解释DMV及其列。

如果size_in_bytes是缓存的计划大小,为什么SQL Server在实际执行计划中说另一个值?

新查询,新数字:

  • 实际计划
    • 缓存的计划大小16KB
    • 编译内存96KB
  • DMV:
    • sys.dm_exec_cached_plans.size_in_bytes 24KB
    • sys.dm_os_memory_objects.pages_in_bytes, .max_pages_in_bytes 16KB。

另外,请注意,此查询不需要任何其他内存授予即可进行排序和哈希操作。

Microsoft SQL Server 2012-11.0.5343.0(X64)

Answers:


12

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_objectsDMF中来找到它们。有两种类型的依赖对象:可执行计划(内存对象= 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_objectsDMV中的条目(上面以粗体指出的项目)相加得出,所有与dm_os_memory_objects.page_allocator_address该编制计划相关。获得正确值的诀窍是首先memory_object_addresssys.dm_exec_cached_plans特定的编译计划中获取,然后使用其根据其字段从中获取对应的MEMOBJ_COMPILE_ADHOC行。然后,从该行中获取值,并使用它从该行中获取具有相同值的所有行。(请注意,该技术不适用于其他缓存对象类型:语法分析树扩展的ProcCLR编译的ProcCLR编译的功能sys.dm_os_memory_objectsmemory_object_addresspage_allocator_addresssys.dm_os_memory_objectssys.dm_os_memory_objectspage_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计划的各个节点匹配。

资源:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.