web-dev-qa-db-ja.com

パラメータ化されていない、自明ではないアドホッククエリプランが再利用される場合

現在、クエリを実行しているデータベースに対して99%のアドホッククエリプランを生成していると思われるアプリケーションを調査しています。これを確認するには、次のステートメントを実行して、クエリプランキャッシュ内のオブジェクトの概要を取得します。

SEエディターにコードを入力できなかったため、スクリーンショット

select statement to query sys.dm_exec_cached_plans

参照:キャッシュの計画とアドホックワークロードの最適化 (SQLSkills.com/K. Tripp)若干の修正あり

上記のクエリの結果は次のとおりです。

CacheType            Total Plans          Total MBs                               Avg Use Count Total MBs - USE Count 1                 Total Plans - USE Count 1
-------------------- -------------------- --------------------------------------- ------------- --------------------------------------- -------------------------
Adhoc                158997               5749.520042                             2             2936.355979                             126087
Prepared             1028                 97.875000                               695           46.187500                               576
Proc                 90                   69.523437                               39659         21.187500                               21
View                 522                  75.921875                               99            0.453125                                3
Rule                 4                    0.093750                                22            0.000000                                0
Trigger              1                    0.070312                                12            0.000000                                0    

プランキャッシュの158'997アドホッククエリのうち、126'087クエリは1回しか実行されていません。

アドホッククエリをさらに調べたところ、一部のクエリが複数回生成されることさえありました。次のクエリを使用してプランキャッシュを調べ、同一の実行プランを取得しました。

SELECT SUM(cplan.usecounts) AS [Unique Same Single Plans],
       qtext.text
FROM   sys.dm_exec_cached_plans AS cplan
       CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS qtext
             CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qplan
       JOIN sys.databases AS sdb
            ON  sdb.database_id = qplan.dbid
WHERE  1 = 1
       AND cplan.objtype = 'Adhoc'   -- <-- only Adhoc plans
       AND sdb.name = 'DATABASENAME' -- <-- for a certain database
       AND cplan.usecounts = 1       -- <-- with a usecounts of 1
GROUP BY
       qtext.text having sum(cplan.usecounts) > 1
ORDER BY
       1 DESC --,cplan.objtype, cplan.usecounts   

参照:覚えていない。それが元々あなたのものだったかどうか教えてください。私がそれを認めます。

これにより、既存の同一のクエリプランと同一のクエリプランと、の一意の同一のクエリプランの合計を持つアドホッククエリのリストが表示されます。計画キャッシュ。

Screenshot for result set containing unique same single plans

編集されたGUIDからわかるように、複数回作成された多くの一意のアドホッククエリプランがあります。


私が正しい方向に進んでいることを証明するために、一意のカウントが3である上からステートメントを取得し、そのステートメントをフィルターとしてプランキャッシュサマリーステートメントで使用して、ステートメントとクエリプランを取得しました。

SELECT cplan.usecounts,
       qtext.text,
       qplan.query_plan
FROM   sys.dm_exec_cached_plans AS cplan
       CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS qtext
       CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qplan
       JOIN sys.databases AS sdb
            ON  sdb.database_id = qplan.dbid
WHERE  1 = 1
       AND cplan.objtype = 'Adhoc'
       AND sdb.name = 'DATABASENAME'
       AND qtext.text = 
           'SELECT description,id,name,osguid,profil FROM omitted WHERE osguid IN (SELECT osgroupguid FROM omitted WHERE osuserguid=''81C4B8_REMOVED_SOME_9DD2'')'
ORDER BY
       1 DESC

参照:覚えていない。それが元々あなたのものだったかどうか教えてください。私がそれを認めます。

これにより、作成されてプランキャッシュに保存された一意のアドホッククエリのリストが表示されます。

Screenshot of result set containing unique same single plans

上記のスクリーンショットの数値は、カウントが3であるため、1つのクエリが既に再利用されていることを示しています。ただし、すべてのクエリは同じです。

ここまで読んだことから、私は次のことを前提としています。

  • アドホッククエリは、SQL Serverクエリオプティマイザーに(おそらく短い)人生で初めて渡されたクエリです
  • パラメータのないステートメントは一意であると見なされ、プランキャッシュにAdhocエントリが作成されます
  • アドホッククエリは取るに足らないものになる可能性があり、同一であっても、ステートメントごとに個別のクエリプランが作成されます。

私は同様に次のことを認識しています。

  • optimize for ad hoc workloadsをオンにすると、1回だけ使用されるアドホックプランのキャッシュ内のクエリプランのサイズがわずかに減少します
  • 私の場合、ALTER DATABASE [DATABASENAME] SET PARAMETERIZATION FORCEDを実行するのは良い考えですが、それは...
    • 制限があります(BrentOzarの記事を参照)
    • プログラムのパラメータ化はより良いでしょう

ご質問

この質問の入力中にポップアップしたすべての記事といくつかの関連する質問を読んだ後、次の2つの質問があります。

  1. パラメータ化されていない、自明ではないアドホッククエリプランが再利用されるのはどの場合ですか?
  2. 同一のステートメントに対して複数のキャッシュされたクエリプランがあるのはなぜですか?

パラメータ化されていないクエリプランは一意であると見なされているため、私の質問が矛盾していることに気づきましたが、なぜ一部のパラメータ化されていないアドホッククエリプランが再利用されるのですか?


@DenisRubashikinのコメントへの応答:

「同一の」クエリの計画をXML形式で保存し、ファイルを比較します。(たとえば、設定されたオプションで)いくつかの違いがある可能性があると思います– Denis Rubashkin 29分前

SETオプションは同じです。計画全体の唯一の違いは、CompileTimeCompileCPU<StatementSetOptions>セクションの後の2行目にあります。以下の両方の関連部分を貼り付けました:

QueryPlan1.xml

      <StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" />
      <QueryPlan CachedPlanSize="32" CompileTime="4" CompileCPU="4" CompileMemory="472">

QueryPlan2.xml

      <StatementSetOptions QUOTED_IDENTIFIER="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false" />
      <QueryPlan CachedPlanSize="32" CompileTime="3" CompileCPU="3" CompileMemory="472">

その他の違いは見つかりませんでした。


この質問のキュレーションに使用された参考資料:

6

アドホックワークロードの最適化をオンにすると、キャッシュ内のクエリプランのサイズがわずかに減少します

...

プランキャッシュの158'997アドホッククエリのうち、126'087は1回しか実行されていません。

アドホック計画の79%を削除することはわずか削減とは呼びません。

パラメータ化されていない、自明ではないアドホッククエリプランが再利用されるのはどの場合ですか?

同じデータベースに接続しているクライアントがプランをキャッシュに入れた後、まったく同じクエリを同じセッション設定で実行します。

そう、

同一のステートメントに対して複数のキャッシュされたクエリプランがあるのはなぜですか?

通常は、クエリの動作に影響を与えるさまざまな設定のセッションです。空白を含むクエリ内のテキストの違いは、これを引き起こす可能性があります。オブジェクトの名前解決が異なるため、ユーザーのデフォルトのスキーマがこれを引き起こす可能性があります。また、ほぼ同時に送信された2つの同一のクエリは、個別に最適化されてキャッシュされる場合があります。