web-dev-qa-db-ja.com

インデックスビューのクラスター化インデックスが選択される要因は何ですか?

簡単
クエリオプティマイザーによるインデックス付きビューのインデックスの選択には、どのような要素が関係していますか?

私にとって、インデックス付きビューは、オプティマイザーがインデックスを選択する方法について私が理解していることを無視しているようです。私は これは前に尋ねました を見ましたが、OPはあまり受け入れられていませんでした。 私は本当にガイドポストを探していますが、疑似例を作り、実際の例をたくさんのDDL、出力、例とともに投稿します。

Enterprise 2008以降を使用していると想定し、with(noexpand)を理解します

疑似例

この疑似例を見てみましょう。22個の結合、17個のフィルター、および1000万行の行の束を横切るサーカスポニーを含むビューを作成します。このビューは具体化するのに費用がかかります(そう、大文字のEが付きます)。ビューをSCHEMABINDしてインデックスを付けます。次にSELECT a,b FROM AnIndexedView WHERE theClusterKeyField < 84。私を回避するオプティマイザロジックでは、基になる結合が実行されます。

結果:

  • ヒントなし:720行の4825読み取り、76ミリ秒で47 cpu、0.30523の推定サブツリーコスト。
  • ヒントあり:17読み取り、720行、4 CPUで15 CPU、0.007253の推定サブツリーコスト

ここで何が起こっているのでしょうか? Enterprise2008、2008-R2、2012で試してみました。すべてのメトリックで、ビューのインデックスを使用する方がはるかに効率的だと考えることができます。これはアドホックなので、パラメータースニッフィングの問題やデータの偏りはありません。

実際の(長い)例

あなたがおそらくこの部分を読む必要がない、または読みたくないマゾヒスティックでない限り。

バージョン
うん、エンタープライズ。

Microsoft SQL Server 2012-11.0.2100.60(X64)Feb 10 2012 19:39:15 Copyright(c)Microsoft Corporation Enterprise Edition(64-bit)on Windows NT 6.2(Build 9200:)(Hypervisor)

ビュー

CREATE VIEW dbo.TimelineMaterialized    WITH SCHEMABINDING
AS
SELECT  TM.TimelineID,
        TM.TimelineTypeID,
        TM.EmployeeID,
        TM.CreateUTC,
        CUL.CultureCode,
        CASE 
           WHEN TM.CustomerMessageID    > 0 THEN TM.CustomerMessageID
           WHEN TM.CustomerSessionID    > 0 THEN TM.CustomerSessionID
           WHEN TM.NewItemTagID         > 0 THEN TM.NewItemTagID
           WHEN TM.OutfitID             > 0 THEN TM.OutfitID
           WHEN TM.ProductTransactionID > 0 THEN TM.ProductTransactionID
           ELSE 0 END  As HrefId,
        CASE 
          WHEN TM.CustomerMessageID    > 0 THEN IsNull(C.Name, 'N/A')   
          WHEN TM.CustomerSessionID    > 0 THEN IsNull(C.Name, 'N/A')
          WHEN TM.NewItemTagID         > 0 THEN IsNull(NI.Title, 'N/A')
          WHEN TM.OutfitID             > 0 THEN IsNull(O.Name, 'N/A')
          WHEN TM.ProductTransactionID > 0 THEN IsNull(PT_PL.NameLocalized, 'N/A')
                 END as HrefText

FROM       dbo.Timeline TM
INNER JOIN dbo.CustomerSession    CS    ON TM.CustomerSessionID    = CS.CustomerSessionID
INNER JOIN dbo.CustomerMessage    CM    ON TM.CustomerMessageID    = CM.CustomerMessageID
INNER JOIN dbo.Outfit             O     ON PO.OutfitID             = O.OutfitID
INNER JOIN dbo.ProductTransaction PT    ON TM.ProductTransactionID = PT.ProductTransactionID
INNER JOIN dbo.Product            PT_P  ON PT.ProductID            = PT_P.ProductID
INNER JOIN dbo.ProductLang        PT_PL ON PT_P.ProductID          = PT_PL.ProductID
INNER JOIN dbo.Culture            CUL   ON PT_PL.CultureID         = CUL.CultureID
INNER JOIN dbo.NewsItemTag        NIT   ON TM.NewsItemTagID        = NIT.NewsItemTagID
INNER JOIN dbo.NewsItem           NI    ON NIT.NewsItemID          = NI.NewsItemID
INNER JOIN dbo.Customer           C     ON  C.CustomerID = CASE 
                                             WHEN TM.TimelineTypeID = 1 THEN CM.CustomerID 
                                             WHEN TM.TimelineTypeID = 5 THEN CS.CustomerID
                                             ELSE 0 END

WHERE        CUL.IsActive = 1

クラスタ化インデックス

CREATE UNIQUE CLUSTERED INDEX PK_TimelineMaterialized  ON 
                   TimelineMaterialized (EmployeeID, CreateUTC, CultureCode, TimelineID)

テストSQL

-- NO HINT - - -  - - -  - - -  - - -  - - - 
SELECT  *                 --yes yes, star is bad ...just a test example
FROM    TimelineMaterialized TM 
WHERE 
            TM.EmployeeID   = 2
        AND TM.CultureCode  = 'en-US'
        AND TM.CreateUTC    > '9/10/2012'
        AND TM.CreateUTC    < '9/11/2012'

-- WITH HINT - - -  - - -  - - -  - - -  - - - 
SELECT  *               
FROM    TimelineMaterialized TM with(noexpand)
WHERE 
            TM.EmployeeID   = 2
        AND TM.CultureCode  = 'en-US'
        AND TM.CreateUTC    > '9/10/2012'
        AND TM.CreateUTC    < '9/11/2012'

結果= 11行の出力

11 rows of output - same for both queries

プロファイラ出力
上位4行にはヒントがありません。下の4行はヒントを使用しています。

Profiler

実行計画
SQLPlan形式の両方の実行プランのGitHub Gist

ヒント実行計画はありません-SQL氏に提供したクラスター化インデックスを使用しないのはなぜですか? 3つのフィルターフィールドでクラスター化されます。試してみてください。
No Hint - huge execution plan

ヒントを使うときのシンプルなプラン。

Using Hint - Simple Execution Plan

19
EBarr

インデックス付きビューの照合は比較的コストのかかる操作*であるため、オプティマイザは他の迅速で簡単な変換を最初に試みます。それらがたまたま安いプラン(あなたのケースでは0.05ユニット)を生み出した場合、最適化は早く終わります。賭けは、継続的な最適化が節約よりも多くの時間を消費するということです。オプティマイザの主な目標は、すぐに「十分に良い」計画であることを思い出してください。

ビューのクラスター化インデックスを使用するそれ自体は高価ではありませんが、論理クエリツリーを潜在的なインデックス付きビューに一致させるプロセスは、高価になる可能性があります。他の質問のコメントで述べたように、クエリのビュー参照は最適化の前に展開されるため、オプティマイザーは最初にビューに対してクエリを記述したことを知りません-展開されたツリーのみが表示されます(まるでビューはインライン化されていました)。

「十分な計画」とは、オプティマイザが適切な計画を見つけ、探索フェーズの早い段階で停止したことを意味します。 「タイムアウト」は、現在のフェーズの開始時に自身が「予算」として設定した最適化ステップの数を超えたことを意味します。

予算は、前のフェーズで見つかった最良の計画のコストに基づいて設定されます。このような低コストのクエリ(0.05)では、予算の移動の数は非常に少なくなり、サンプルクエリに含まれる結合の数を考えると、定期的な変換によってすぐに使い果たされます(たとえば、内部結合を再配置する方法はたくさんあります)。 。

インデックス付きビューのマッチングが高価で、最適化の後の段階に残される、またはよりコストのかかるクエリのみが考慮される理由について詳しく知りたい場合は、トピックに関する2つのマイクロソフトリサーチペーパー here を参照してください。 (pdf)および here (citeseer)。

もう1つの関連する要素は、インデックス付きビューのマッチングが最適化フェーズ0(トランザクション処理)では使用できないことです。

参考文献:

インデックス付きビューと統計

*およびEnterprise Edition(または同等のもの)でのみ利用可能

26
Paul White 9