web-dev-qa-db-ja.com

キャッシュサイズと予約メモリを計画する

実際の実行プランを含むクエリを実行すると、ルート演算子(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_bytesの値が49152(48KB)であることを理解できません。私はこれらすべての列、特にsize_in_bytesについてBOLを読みました:

"キャッシュオブジェクトによって消費されるバイト数。"

パズルの実際の意味を理解するために、パズルの最後の部分を配置することはできません。

すべての演算子(並べ替えとハッシュに使用される追加のメモリ許可について話しているのではない)は、状態の保存、計算などを行うために一定量の固定メモリを必要とすることを知っています。

だから、私の質問は:

  • size_in_bytesの意味
  • 「キャッシュされたプランのサイズ」よりも値が高いのはなぜですか?
  • 予約されているすべてのオペレーター/イテレーター用の固定メモリ量はどこですか、それは「キャッシュされた計画サイズ」(私の例では32Kb)ですか、それとも他の場所ですか?

私はそれらが異なる機能を持つ異なるDMVであることを知っていますが、それらは関連しています。 sys.dm_exec_cached_plansでコンパイルされた(キャッシュされた)プランは、sys.dm_os_memory_objects列でmemory_object_addressに結合します。私がここに質問を投稿する理由は、DMVとその列を解釈する方法を理解して、これについて助けを求めているからです。

size_in_bytesがキャッシュされたプランのサイズである場合、SQL Serverが実際の実行プランで別の値を言うのはなぜですか?

新しいクエリ、新しい番号:

  • 実際の計画
    • キャッシュされた計画サイズ16KB
    • CompileMemory 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)
18
GordonLiddy

少なくとも「コンパイル済みプラン」に関して、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_handlesys.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 TreeExtended ProcCLR 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_STATEMENTsys.dm_os_memory_objectsとしてマークされた行がクエリごとに1つ必要です。これらの行のpages_in_bytesフィールドは、XMLプランの個​​々の<QueryPlan>ノードと一致する必要があります。

リソース:

12
Solomon Rutzky

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のメモリを使用するようになりました

enter image description here

enter image description here

1
Ali varzeshi