sql >> データベース >  >> RDS >> Sqlserver

クエリ オプティマイザーがインデックス付きビューのインデックスを完全に無視するのはなぜですか?

    tl;dr 回答:NOEXPAND を指定しない場合、クエリ オプティマイザは、ビューから単純な選択を送信していることを認識しません。クエリの展開 (表示されるのはこれだけです) をビュー インデックスと一致させる必要があります。多数のキャストを含む 5 方向結合の場合は、おそらく気にしないでしょう。

    クエリに対するビュー インデックスのマッチングは難しい問題です。クエリ エンジンがインデックスに一致するにはビューが複雑すぎると思います。次のクエリを検討してください:

    SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';
    

    これがビュー インデックスを使用できることは明らかですが、これはクエリ エンジンが認識するクエリではありません。 NOEXPAND を指定しない場合、ビューは自動的に展開されるため、これがクエリ エンジンに送信されます。

    SELECT ID, Code1 FROM (
        SELECT e.ID, 'NR'+CAST(c1.CODE as nvarchar(11)) as Code1, 'NR'+CAST(c2.CODE as nvarchar(11)) as Code2, 'NR'+CAST(c3.CODE as nvarchar(11)) as Code3, 'NR'+CAST(c4.CODE as nvarchar(11)) as Code4, 'NR'+CAST(c5.CODE as nvarchar(11)) as Code5
        FROM dbo.Entity e
            inner join  dbo.Classificator1 c1 on e.ID = c1.ID
            inner join  dbo.Classificator2 c2 on e.ID = c2.ID
            inner join  dbo.Classificator3 c3 on e.ID = c3.ID
            inner join  dbo.Classificator4 c4 on e.ID = c4.ID
            inner join  dbo.Classificator5 c5 on e.ID = c5.ID;
    ) AS V;
    

    クエリ エンジンはこの複雑なクエリを認識し、定義されたビュー インデックスを記述する情報 (ただし、おそらくビュー定義の SQL ではない) を持っています。このクエリとビュー インデックスの両方に複数の結合とキャストがあることを考えると、一致させるのは難しい仕事です。

    このクエリとビュー インデックスでは、結合と一致が同一であることはわかっていますが、クエリ プロセッサはそれを認識していないことに注意してください。このクエリは、Classificator3 の 5 つのコピーを結合した場合、または列の 1 つが 'NQ'+CAST(c2.CODE as varchar(12)) であった場合とまったく同じように扱われます。ビュー インデックス マッチャー (この複雑なクエリを照合しようとした場合) は、このクエリのすべての詳細を、関連するテーブルのビュー インデックスの詳細と照合する必要があります。

    クエリ エンジンの最大の目標は、クエリを効率的に実行する方法を見つけることです。おそらく、5 方向結合と CAST のすべての詳細をビュー インデックスに一致させるために多くの時間を費やすようには設計されていません。

    推測する必要がある場合、ビュー インデックス マッチャーは、クエリの結果の列が基になるテーブルの列ではなく (CAST のため)、単に何もしようとしないことを認識していると思われます。 追加 :私は間違っています。統計を更新してクエリを高価にするという Martin の提案を試してみたところ、NOEXPAND を使用せずにこれらのクエリの一部にビュー インデックスが一致しました。ビューマッチャーは思ったより賢いです!したがって、問題は、コストが非常に高い場合、ビュー マッチャーが複雑なクエリの照合をより困難にしようとすることです。

    クエリ エンジンがここで一致するものを把握できると期待する代わりに、NOEXPAND ヒントを使用します。 NOEXPAND は絶対にあなたの友達です。なぜなら、クエリ エンジンが見られるからです

    SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';
    

    これで、ビュー インデックス マッチャに有用なインデックスがあることがすぐにわかります。

    (注:SQL Fiddle コードには、同じテーブルへの 5 つの外部キー参照がすべて含まれていますが、これはおそらく必要なものではありません。)



    1. リクエストはHTTPステータス401で失敗しました:Unauthorized IN SSRS

    2. MySqlは、列名として動的な行の値を選択します

    3. このMySQLSELECTクエリをDELETEクエリに変換するにはどうすればよいですか?

    4. インデックス付きビューにMAX()集計を含めることができないのはなぜですか?