web-dev-qa-db-ja.com

推奨インデックス

私は一般的にインデックス作成に不慣れで、クエリプランなどについて学び始めたばかりです。次のインデックスを作成するようにアドバイスし続けるこの1つの特定のクエリに取り組んでいます。

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Company] ([CreatedById],[TenantId],[CreatedDate])

enter image description here

私はすでに次のインデックスを作成しています:

CREATE NONCLUSTERED INDEX [IX_Company_Tenant] 
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate])

私が疑問に思っているのは、作成済みのインデックスを次のように変更した場合、同じ結果で速度が向上するかどうかです。

CREATE NONCLUSTERED INDEX [IX_Company_Tenant] 
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate], [CreatedByID])

クエリストアによって提案されているインデックスを作成する代わりに?

[〜#〜]編集[〜#〜]

3番目のインデックスを適用した後でも:

CREATE NONCLUSTERED INDEX [IX_Company_Tenant] 
ON [dbo].[Company] ([TenantId],[UserId],[CreatedDate], [CreatedByID])

私はまだ同じ提案されたインデックスを取得します。

2
Owain Esau

まず、インデックスの作成の間に、そのクエリのキャッシュされたプランをダンプしていることを確認してください。核となるオプションは、キャッシュフラッシュ( DBCC FREEPROCCACHE )を実行することですが、プランハンドルを探して、特定のハンドルを実行することもできます。また、実験の合間に非クラスター化インデックスを削除することをお勧めします。このテーブルに3つのインデックスがあり、すべて同じクエリを高速化しようとしている場合、それは最大の状況ではありません。

インデックスの作成を検討するときは、SQLが提供するインデックス作成の提案の価値が限られていることに注意してください。 SQLは通常、「ここでインデックスを使用してより良い仕事をすることができます」と言ったときに正しく理解しますが、ニーズに最適な正確なインデックスを伝える良い方法は実際にはありません。

ほとんどの場合、列の順序は最適ではありません。多くの場合、有用な列を見逃したり、入力しすぎるように指示したりします。

一般に、インデックスの必要性を引き起こしているクエリをしっかりと理解してから、そのクエリに適合するインデックスを作成する必要があります。ほとんどのクエリは、特定のレコードセットへのホーミングの形式をとるため、インデックス内の列は、目的のデータに最も適したものから最も少ないものの順に配置されます。つまり、ある列ですべての可能な結果の95%を削除でき、別の列で結果の20%を削除できる場合は、95%の列を最初に配置します。

簡単な例として、日付でレコードの小さな(1%)サブセットを選択し、残りのレコードの50%が持つフラグを介して残りのレコードの一部を削除するクエリがある場合は、注文する方がはるかに良いでしょう。最初に日付で列にインデックスを付け、次にフラグでインデックスを付けます。逆にすると、同じ最終結果を得るためにより多くの作業を実行することになります。

データを知らずにクエリを見ると、かなり良いインデックスになると思います。

CREATE NONCLUSTERED INDEX [IX_Company_Tenant] 
ON [dbo].[Company] ([CreatedDate],[CreatedByID],[TenantId])

これはそれをより詳細に説明する良いブログ記事です--- https://www.brentozar.com/archive/2019/10/how-to-think-like-the-sql-server-engine-adding -a-nonclustered-index /

1
Rob Pearson

提案された正確な列の順序で(または技術的にほぼ同等の列の順序で)インデックスを作成する必要があります。
列の順序は、特定のクエリのインデックスの使いやすさと効率性にとって重要な場合があります。

上記の場合、SQLServerを許可するにはCreatedDateCreatedByIDTenantIdの後ろ、またはこれらのフィールドのすぐ後ろに置くことが重要です(したがって、間にUserIdはありません)。 CreatedByIDTenantIdのインデックスブロックに直接ジャンプし、その列の連続する注文エントリ内で要求されたCreatedDate開始値を見つけて、すべての行参照を1つずつ読み取ります。もう1つは、要求されたCreatedDate終了値に達するまでインデックスをスクロールします(そして、見つかった各行のカウンターをインクリメントします)。

それとは反対に、あなたの調整されたインデックスについて考えてください。
SQLサーバーは、要求されたTenantIdの領域を見つけることができます。ただし、そのTenantIdのすべてのエントリを読み取り、CreateDateが範囲内にあるかどうかを確認し、範囲内にある場合は、CreatedByIDがクエリ条件を満たすかどうかを確認する必要があります。これらは、テーブルサイズとデータ分散に応じて、これらのチェックが必要な非常に多くの行になる可能性があります。

1
EOhm