web-dev-qa-db-ja.com

SQL Server:すべての列を含むインデックスをカバーしていますか?

私たちのチームはアプリケーションと関連するデータベースを継承しています。以前の開発者は、すべてのテーブルのすべてのインデックスにINCLUDE句があり、キーの一部ではないすべての列を常に追加するというルールを適用していたようです。これらのテーブルには、平均して2〜5個のインデックスまたは一意の制約と外部キーがあります。

アクセスはデフォルトで(常にではないが)すべての列を取得するORMを介して行われるため、データベースでスローされるクエリに関係なく、SELECTのパフォーマンスを向上させることを目的としています。この副作用として、ストレージ要件の増加(大幅に増加する可能性があります)と、INSERT/UPDATE/DELETEのオーバーヘッド時間が増加すると予想されます。

問題は、これは賢明な戦略ですか?私たちのチームにはSQL Serverの歴史がありますが、内部動作について専門家であると考えるメンバーはいません(ただし、この戦略が最適である場合、今のところデフォルトではないのではないかという質問が出されています)。他にどのような副作用(データベースサーバーのCPU /メモリ/ TempDBの使用など)が予想されますか、または上記の仮定の一部が正しくありませんか?

さらに、アプリケーションは、オンプレミスのSQL Server(2012年以降のバージョン)とAzure SQLの両方にインストールできます-この結果として、2つの違い、またはAzureへの追加の副作用に備えておく必要があります。アプローチ?

9
T2PS

これまで、特定のインデックスに対してこれを実行して、頻繁に実行される大量のクエリを支援しました。実際に彼らが行ったことは、複数のクラスター化インデックスを作成することです。これらのインデックスのいずれかを使用して行を検索する場合、実際のクラスター化インデックス(または実際のクラスター化インデックスがない場合はヒープ)の残りのデータを検索する追加の作業は必要ありません。 。

これは賢明な戦略ですか?

特定のクエリパターンをサポートする必要がある一部のインデックスでは、確かにそうです。

しかし、これをallインデックスで行うには、間違いなく「いいえ」と言います。

実際に必要のない場所で行うにはスペースが無駄になり、挿入/更新が大幅に遅くなります。各インデックスページが保持するレコードが少なくなるため、フィルター処理のためにインデックスのチャンクを参照する必要があるが、他のすべての列を使用する必要がないクエリは、より多くのページにアクセスする必要があるため、読み取りクエリが遅くなる可能性があります。これにより、データベースのメモリ消費量が増加します。これらのページはバッファプールにロードする必要があり、メモリが不足している場合、他の有用なページを排出する可能性があります。これらのインデックスで圧縮を使用して、ストレージとメモリの要件への影響を軽減しようとすると、代わりにCPUに余分な負荷がかかります。

デフォルトでは(常にではないが)すべての列を取得するORMを介してアクセスするため

これはORM(または単純なORM)の最適化が不十分な一般的なパターンであり、これらの場合、SQL Serverのインデックスアドバイザー(および類似のサードパーティツール)が多数のINCLUDEd列を持つインデックスを提案するので、これがインデックスがこの方法で作成された理由であるというあなたの提案に同意します。

しかし、そのようなクエリはすべて少し速くなり、一部は大幅に速くなる可能性がありますが、多くの場合、メリットは非常に小さいため、共通のワーキングセット、ディスク上のスペースに必要な追加のメモリフットプリントに値しないと思いますIOディスクとメモリの間。

また、ORMは、クエリが関連するすべてのテーブルのすべての列を選択していない可能性があるため、現在のリクエストのメインターゲットにのみメリットがあり、他のオブジェクトがフィルタリングに使用されている場合、インデックスが大きいとクエリにペナルティが科される可能性があることにも注意してください。データを返さない(SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')おそらく)。

特にデータが大きい場合に使用される余分なスペースについてのもう1つの考慮事項は、バックアップ戦略に影響を与えることです。つまり、これらのバックアップのストレージと転送のコスト、潜在的な復元時間などです。

2つの[オンプレミスとAzureSQL]の違いに備えるべきか

一般に、ここでの考慮事項はいずれの場合も同じになると思いますが、大きなインデックスによって課される過剰なメモリ/ IOコストは、サービス層を微調整できるAzureでより直接的に見えるため、インフラストラクチャコストをより簡単にハードウェアリソースのセットが比較的固定されている。 vcoreベースの価格設定の代わりに標準/プレミアム階層を使用する場合、IO標準のコストはプレミアムに含まれるため、DTUあたりIO 。Azureでマルチリージョンバックアップや冗長性などのローカル以外の機能を使用している場合は、不必要に広いインデックスが占める余分なスペースに関連する帯域幅コストが発生する可能性があります。

8
David Spillett

問題は、これは賢明な戦略ですか?...(この戦略が最適だったとしても、今ではデフォルトではないという疑問が提起されていますが)

ほとんどの場合、これは賢明な戦略ではありません。その理由は、一般的にOLTPデータベースの場合、エンドユーザーに返される行は全体ではないためです(Generalization)

あなたが自問すべき問題は、キー列でシークしている場合、そのシーク操作によって返される行数は何ですか?そして、その列を検索するクエリについても同じことを繰り返します。

たくさんの列を返す次の表を検討してください。where SelectiveIDField= ...

select columnA,columnC, ... columnZ
FROM dbo.BigTable
Where SelectiveIDField= '225122141';

selectiveIDFieldでのシークによって1行のみが返される場合、追加のキー検索は悪いことですか? (ここにクラスター化されたインデックスがあると思いますが、そうでなければRIDルックアップ)

これは、1つの追加のキールックアップ、1つの追加の実行+結合演算子を実行するだけです。それが10であっても100であっても、それは大きな影響を与えますか?これは、クエリの実行量と実行時間の重要性にも依存します。

無視できる場合は、SelectiveIDFieldにインデックスを作成し、1日で呼び出すだけです。書き込み損失と比較して、読み取り利得の価値はありません。

要するに、テーブル全体にインデックスを作成することは、クエリに実際に問題があり、カバーするインデックス全体を追加することで大幅に改善できる場合を除いて、デフォルトのアプローチではないはずです。

5
Randi Vertongen