実際の実行プランを含むクエリを実行すると、ルート演算子(SELECT
)によってキャッシュされたプランのサイズが32KBであることがわかります。
問題のプランを見て、sys.dm_exec_cached_plans
とsys.dm_os_memory_objects
を結合するクエリは、pages_in_bytes
とmax_pages_in_bytes
の値が32768(32KB)であり、キャッシュされたプランのサイズと一致することを示しています。
sys.dm_exec_cached_plans.size_in_bytes
の値が49152(48KB)であることを理解できません。私はこれらすべての列、特にsize_in_bytes
についてBOLを読みました:
"キャッシュオブジェクトによって消費されるバイト数。"
パズルの実際の意味を理解するために、パズルの最後の部分を配置することはできません。
すべての演算子(並べ替えとハッシュに使用される追加のメモリ許可について話しているのではない)は、状態の保存、計算などを行うために一定量の固定メモリを必要とすることを知っています。
だから、私の質問は:
size_in_bytes
の意味私はそれらが異なる機能を持つ異なるDMVであることを知っていますが、それらは関連しています。 sys.dm_exec_cached_plans
でコンパイルされた(キャッシュされた)プランは、sys.dm_os_memory_objects
列でmemory_object_address
に結合します。私がここに質問を投稿する理由は、DMVとその列を解釈する方法を理解して、これについて助けを求めているからです。
size_in_bytes
がキャッシュされたプランのサイズである場合、SQL Serverが実際の実行プランで別の値を言うのはなぜですか?
新しいクエリ、新しい番号:
sys.dm_exec_cached_plans.size_in_bytes
24KBsys.dm_os_memory_objects.pages_in_bytes, .max_pages_in_bytes
16KB。また、このクエリでは、並べ替えやハッシュ操作のために追加のメモリを付与する必要がないことに注意してください。
Microsoft SQL Server 2012-11.0.5343.0(X64)
少なくとも「コンパイル済みプラン」に関して、size_in_bytes
DMVのsys.dm_exec_cached_plans
フィールドがXMLプランのCachedPlanSize
ノードのQueryPlan
属性よりも大きいのは、コンパイル済みプランが原因です。クエリプランと同じではありません。コンパイル済みプランは複数のメモリオブジェクトで構成され、それらの合計サイズはsize_in_bytes
フィールドに相当します。したがって、ドキュメントで見つけた「キャッシュオブジェクトによって消費されたバイト数」の説明は正確です。 DMVの名前が与えられたときに「キャッシュオブジェクト」が何を意味するのかを誤って解釈するのは簡単であり、「計画」という用語には複数の意味があります。
コンパイル済みプランは、クエリ batch (つまり、単一のステートメントだけではない)に関連するさまざまな情報を保持するコンテナであり、それらの1つ(または複数)がクエリプラン( s)。コンパイルされたプランには、最上位のメモリオブジェクトMEMOBJ_COMPILE_ADHOCがあります。これは、両方のDMVのsys.dm_os_memory_objects
フィールドを介してリンクされているmemory_object_address
の行です。このメモリオブジェクトには、シンボルテーブル、パラメータコレクション、関連オブジェクトへのリンク、アクセサキャッシュ、TDSメタデータキャッシュ、および場合によってはその他のアイテムが含まれます。コンパイルされたプランは、同じ batch を同じセッション設定で実行しているセッション/ユーザー間で共有されます。ただし、一部の関連オブジェクトは、セッション/ユーザー間で共有されないです。
コンパイル済みプランには、plan_handle
(sys.dm_exec_cached_plans
内)をsys.dm_exec_cached_plan_dependent_objects
DMFに渡すことによって検出できる1つ以上の依存オブジェクトも含まれます。依存オブジェクトには、実行可能プラン(メモリオブジェクト= MEMOBJ_EXECUTE)とカーソル(メモリオブジェクト= MEMOBJ_CURSOREXEC)の2種類があります。カーソルごとに1つずつ、0個以上のCursorオブジェクトがあります。同じ batch を実行するユーザーごとに1つ以上の実行可能プランオブジェクトが1つ以上あるため、実行可能プランは not ユーザー間で共有されます。実行可能プランには、実行時パラメーターとローカル変数情報、現在実行中のステートメントなどの実行時状態、実行時に作成されたオブジェクトのオブジェクトID(これは、テーブル変数、一時テーブル、一時ストアドプロシージャなどを指すと想定しています) 、およびおそらく他のアイテム。
マルチステートメントバッチ内の各ステートメント /は、コンパイル済みステートメント内に含まれています(メモリオブジェクト= MEMOBJ_STATEMENT)。各コンパイル済みステートメント(つまりpages_in_bytes
)を1024で割ったサイズは、XMLプランのCachedPlanSize="xx"
ノードの<QueryPlan>
値と一致する必要があります。コンパイルされたステートメントには、多くの場合、関連付けられたランタイムクエリプラン(メモリオブジェクト= MEMOBJ_XSTMT)が1つ(おそらくそれ以上)あります。最後に、クエリであるランタイムクエリプランごとに、クエリ実行コンテキストが関連付けられている必要があります(メモリオブジェクト= MEMOBJ_QUERYEXECCNTXTFORSE)。
コンパイル済みステートメントに関して、単一ステートメントのバッチには、個別のコンパイル済みステートメント(つまりMEMOBJ_STATEMENT)または個別のランタイムクエリプラン(つまりMEMOBJ_XSTMT)オブジェクトはありません。これらの各オブジェクトの値は、メインのコンパイル済みプランオブジェクト(つまりMEMOBJ_COMPILE_ADHOC)に格納され、その場合、そのメインオブジェクトのpages_in_bytes
値を1024で除算すると、CachedPlanSize
XMLプランの<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
を取得し、次にそれを使用してsys.dm_os_memory_objects
フィールドに基づいてmemory_object_address
から対応するMEMOBJ_COMPILE_ADHOC行を取得することです。次に、その行のpage_allocator_address
からsys.dm_os_memory_objects
値を取得し、それを使用して、sys.dm_os_memory_objects
から同じpage_allocator_address
値を持つすべての行を取得します。 (この手法は他のキャッシュオブジェクトタイプでは機能しないことに注意してください:Parse Tree、Extended Proc、CLR Compiled Proc、- CLRコンパイル済み関数。)
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
に一致する関連メモリオブジェクトのSUMです(つまり、size_in_bytes
)。AllocatedBytes
フィールドはTotalPlanBytes
より大きくなる場合があります(つまり、size_in_bytes
)。これは主に再コンパイルが原因で発生しているようです(usecounts
フィールドに1
が表示されていることで明らかです)。BaseSingleStatementPlanKB
フィールド should は、XMLのCachedPlanSize
ノードのQueryPlan
属性と一致しますが、のみ単一のクエリバッチを使用する場合。MEMOBJ_STATEMENT
にsys.dm_os_memory_objects
としてマークされた行がクエリごとに1つ必要です。これらの行のpages_in_bytes
フィールドは、XMLプランの個々の<QueryPlan>
ノードと一致する必要があります。リソース:
Pro SQL Server Internalsがこの問題を調査しました。
dbcc freeproccache
GO
DECLARE
@SQL nvarchar (MAX)
,@I INT = 0
while @I < 1000
BEGIN
SELECT @SQL = N'declare @C int;select @C=ID from dbo.Employees where ID='
+ CONVERT (nvarchar (10), @I);
EXEC (@SQL);
SELECT @I += 1;
END
GO
SELECT
p.usecounts, p.cacheobjtype, p.objtype, p.size_in_bytes, t.[text]
FROM
sys.dm_exec_cached_plans p CROSS apply
sys.dm_exec_sql_text (p.plan_handle) t
WHERE
p.cacheobjtype LIKE 'Compiled Plan%' AND
t.[text] LIKE '%Employees%'
ORDER BY
p.objtype DESC;
1,000のプランがキャッシュされ、それぞれが32 KBのメモリまたは合計32 MBを使用します。推測できるように、ビジーなシステムでのアドホッククエリは、プランのキャッシュメモリの使用量が過剰になる可能性があります。
exec sys.sp_configure N'optimize for ad hoc workloads', N'1';
reconfigure with override;
アドホックワークロードの最適化設定を有効にすると、プランのキャッシュコンテンツが表示されます。ご覧のように、以前使用していた32 MBではなく、272 KBのメモリを使用するようになりました