web-dev-qa-db-ja.com

データベースインデックスが多すぎますか?

私はかなり大きなOracleデータベースを使用するプロジェクトに取り組んでいます(ただし、私の質問は他のデータベースにも同様に当てはまります)。ユーザーがフィールドのあらゆる組み合わせを検索できるWebインターフェイスがあります。

これらの検索を高速化するために、ユーザーがよく検索すると思われるフィールドおよびフィールドの組み合わせにインデックスを追加しています。ただし、顧客がこのソフトウェアをどのように使用するかは実際にはわからないため、どのインデックスを作成するかを判断するのは困難です。

スペースは問題ではありません。 4テラバイトのRAIDドライブがあり、そのうちのごく一部しか使用していません。ただし、インデックスが多すぎるとパフォーマンスが低下する可能性が心配です。これらのインデックスは、行が追加、削除、または変更されるたびに更新する必要があるため、単一のテーブルに多数のインデックスを作成するのは悪い考えだと思います。

それで、いくつのインデックスが多すぎると考えられますか? 10? 25? 50?それとも、本当に、本当に一般的で明白なケースをカバーし、他のすべてを無視する必要がありますか?

108
Eli Courtwright

テーブルで発生する操作に依存します。

SELECTが多く、変更がほとんどない場合は、必要なものすべてにインデックスを付けてください。これらは(潜在的に)SELECTステートメントを高速化します。

テーブルがUPDATE、INSERT + DELETEによって頻繁にヒットする場合、これらの操作のいずれかが実行されるたびにすべてを変更する必要があるため、多くのインデックスでは非常に遅くなります

そうは言っても、何もしないテーブルに多くの無意味なインデックスを明確に追加できます。 2つの異なる値を持つ列にBツリーインデックスを追加しても、データの検索に関して何も追加されないため、意味がありません。列内の値が一意であればあるほど、インデックスの恩恵を受けます。

85
cagcowboy

私は通常このように進みます。

  1. 通常の日にデータに対して実行されたrealクエリのログを取得します。
  2. インデックスを追加して、最も重要なクエリが実行プランのインデックスにヒットするようにします。
  3. 更新または挿入の多いフィールドのインデックス作成を避けるようにしてください
  4. いくつかのインデックスの後、新しいログを取得して繰り返します。

すべての最適化と同様に、要求されたパフォーマンスに達すると停止します(これは明らかに、ポイント0が特定のパフォーマンス要件を取得することを意味します)。

43
Sklivvz

他の皆はあなたにすばらしいアドバイスを与えています。あなたが前進するとき、私はあなたのために追加の提案をします。ある時点で、最適なインデックス作成戦略を決定する必要があります。しかし、最終的には、最良の計画されたインデックス作成戦略は、結局は使用されないインデックスを作成することになります。使用されていないインデックスを見つけることができる1つの戦略は、インデックスの使用を監視することです。これは次のように行います。

alter index my_index_name monitoring usage;

その後、v $ object_usageをクエリすることで、その時点からインデックスが使用されているかどうかを監視できます。これに関する情報は Oracle®Database管理者ガイド にあります。

テーブルを更新する前にインデックスを削除してから再作成するウェアハウス戦略がある場合は、インデックスを監視用に再度設定する必要があり、そのインデックスの監視履歴は失われることに注意してください。

26
Mike McAllister

データウェアハウジングでは、非常に多くのインデックスを作成することが一般的です。 200列と190列のインデックスが設定されたファクトテーブルを使用しました。

これにはオーバーヘッドがありますが、データウェアハウスでは通常1回だけ行を挿入するというコンテキストで理解する必要がありますが、更新することはありませんが、その後、何千ものSELECTクエリに参加できます。列。

最大の柔軟性を実現するために、データウェアハウスは通常、(圧縮された)btreeインデックスを使用できるカーディナリティの高い列を除き、単一列のビットマップインデックスを使用します。

インデックスメンテナンスのオーバーヘッドは、主に非常に多くのブロックへの書き込みの費用に関連し、その列の既存の値範囲の「中間」にある値で新しい行が追加されると、ブロックが分割されます。これは、パーティションを作成し、パーティション分割スキームに合わせて新しいデータのロードを調整し、直接パス挿入を使用することで軽減できます。

あなたの質問にもっと直接対処するために、最初は明白なものにインデックスを付けることはおそらく良いと思いますが、テーブルに対するクエリが利益を得るならば、インデックスを追加することを恐れないでください。

14
David Aldridge

Einstein の言い換えでは、シンプルさについて、必要なだけインデックスを追加し、それ以上は追加しません。

ただし、テーブルにデータを追加するたびに、追加するすべてのインデックスにメンテナンスが必要です。主に読み取り専用のテーブルでは、多くのインデックスが適しています。高度に動的なテーブルでは、少ない方が優れています。

私のアドバイスは、一般的で明白なケースをカバーし、特定のテーブルからデータを取得する速度を上げる必要がある問題が発生したら、その時点でインデックスを評価して追加することです。

また、インデックス付けを必要とする新しいものや、何にも使用されておらず削除する必要がある作成済みのインデックスがあるかどうかを確認するために、インデックススキームを数か月ごとに再評価することをお勧めします。

12
Josef

実際のプロジェクトと実際のMySqlデータベースでいくつかの簡単なテストを行いました。私はすでにこのトピックで回答しました: 複数のdb列のインデックス作成のコストは?

しかし、ここで引用した方が良いと思います:

実際のプロジェクトと実際のMySqlデータベースを使用して、いくつかの簡単なテストを行いました。

私の結果は次のとおりです。テーブルに平均インデックス(インデックスの1〜3列)を追加すると、挿入が2.1%遅くなります。したがって、20個のインデックスを追加すると、挿入は40〜50%遅くなります。ただし、選択は10〜100倍高速になります。

それで、多くのインデックスを追加しても大丈夫ですか? -それは依存します:)私はあなたに私の結果を与えました-あなたが決めます!

6
nightcoder

他の全員が指摘した点に加えて、コストベースオプティマイザーは、考慮するインデックスの数が多いため、SQLステートメントのプランを作成するときにコストが発生します。これを減らすには、バインド変数を正しく使用して、SQLステートメントがSQLキャッシュに残るようにします。その後、Oracleはソフト解析を実行し、前回検出したプランを再利用できます。

いつものように、単純なものはありません。歪んだ列とヒストグラムがある場合、これは悪い考えです。

Webアプリケーションでは、許可する検索の組み合わせを制限する傾向があります。そうでなければ、パフォーマンスのために文字通りすべての組み合わせをテストして、誰かがいつか見つかるような潜在的な問題がないことを確認する必要があります。また、リソース制限を実装して、これを停止し、何か問題が発生した場合にアプリケーションの他の場所で問題が発生するようにしました。

6
WW.

最終的に必要なインデックスの数は、データベースサーバー上にあるアプリケーションの動作に依存します。

一般に、挿入する回数が増えるほど、インデックスの痛みは大きくなります。挿入を行うたびに、そのテーブルを含むすべてのインデックスを更新する必要があります。

アプリケーションの読み取り量がまともな場合、または読み取りがほぼすべての場合、さらに少ないコストでパフォーマンスが大幅に向上するため、インデックスを使用する方法があります。

3
Orion Adrian

私の意見には静的な答えはありません。この種のことは「パフォーマンスチューニング」に該当します。

アプリが行うすべてが主キーによって検索されることもあれば、フィールドの無制限の組み合わせに対してクエリが実行され、特定のいずれかがいつでも使用される可能性があるということもあります。

インデックスを作成するだけでなく、計算された検索フィールド、分割テーブルなどを含むようにDBを再編成します-負荷の形状とクエリパラメーター、クエリによって「本当に」必要なデータの量/量に本当に依存します。

すべてのアドホッククエリを気にする必要がないため、DB全体がストアドプロシージャファサードに面している場合、回転が少し簡単になります。または、DBにヒットするクエリの種類を深く理解している可能性があり、チューニングをそれらに限定できます。

SQL Serverの場合、データベースエンジンチューニングアドバイザーが役立つことがわかりました。「典型的な」ワークロードを設定すると、インデックスと統計の追加/削除に関する推奨事項を作成できます。他のDBにも同様のツールがあり、「公式」またはサードパーティのいずれかであると確信しています。

3
scotta

これは実際には実用的というよりも理論的な質問です。インデックスのパフォーマンスへの影響は、使用しているハードウェア、Oracleのバージョン、インデックスタイプなどによって異なります。昨日、Oracleが11gデータベースで10倍高速に動作するHP製の専用ストレージを発表したと聞きました。あなたの場合については、いくつかの解決策があります。これは、テーブルが毎日何千もの更新/削除を取得する場合に特に便利です。 2.テーブルをパーティション分割します(データモデルを適用する場合)。 3.新規/更新されたデータに別のテーブルを使用し、データを結合する夜間プロセスを実行します。これには、アプリケーションロジックの変更が必要です。 4.データがこれをサポートしている場合、IOT(インデックス編成テーブル)に切り替えます。

もちろん、そのような場合にはもっと多くの解決策があるかもしれません。最初の提案は、DBを開発環境に複製し、それに対してストレステストを実行することです。

3
Moshe

主に読み取りを行う(および更新をほとんど行わない)場合、インデックスを作成する必要があるすべてをインデックスに登録しない理由はありません。頻繁に更新する場合は、インデックスの数に注意する必要があります。難しい数字はありませんが、物事が遅くなり始めることに気付くでしょう。クラスター化インデックスが、データに基づいて最も意味のあるものであることを確認してください。

2
Bob King

考えられることの1つは、検索の標準的な組み合わせを対象とするインデックスを構築することです。 column1が一般的に検索され、column2が頻繁に使用され、column3がcolumn2およびcolumn1とともに使用される場合、column1、column2、column3の順序でのインデックスは、これら3つの状況のいずれにも使用できますが、維持する必要があるインデックスは1つだけです。

2

インデックスは、基になるテーブルが更新されるときにコストを課します。インデックスは、クエリを高速化するために使用される場合に利点があります。インデックスごとに、コストと利益のバランスを取る必要があります。インデックスなしでクエリの実行はどれくらい遅くなりますか?どれだけのメリットが高速に実行されていますか?あなたまたはあなたのユーザーは、インデックスが欠落しているときの遅い速度を許容できますか?

更新を完了するのにかかる追加の時間を許容できますか?

コストと利点を比較する必要があります。それはあなたの状況に特有です。 「多すぎる」というしきい値を超える魔法のようなインデックスの数はありません。

インデックスを保存するために必要なスペースのコストもありますが、あなたの状況ではそれは問題ではないと言いました。ディスクスペースがどれだけ安くなったかを考えると、ほとんどの状況で同じことが言えます。

2
Walter Mitty

SQL Serverには、実際に使用されているインデックスを確認できる優れたツールがいくつか用意されています。この記事、 http://www.mssqltips.com/tip.asp?tip=1239 は、インデックスがどの程度使用されているかについてより良い洞察を得ることができるクエリを提供します。どのくらい更新されますか。

1
aboy021

列はいくつありますか?私は常に、マルチカラムインデックスではなく、シングルカラムインデックスを作成するように言われてきました。したがって、インデックスの数は、列の量(IMHO)を超えません。

1
lamcro

実際には、更新されるよりもはるかに頻繁に使用されることがわかっている場合(および使用統計を収集することを意味する場合が多い)を除き、インデックスを追加しないでください。

その基準を満たさないインデックスは、それが使用された奇妙な場合にそれを持たないことによるパフォーマンスのペナルティよりも、再構築するために多くの費用がかかります。

Where句で使用されている列に完全に基づいています。そして、ルールの親指として、DEADLOCKSを回避するために外部キー列にインデックスが必要です。 AWRレポートは、インデックスの必要性を理解するために定期的に分析する必要があります。

0
P Sharma