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


109

かなり大きなOracleデータベースを使用するプロジェクトで作業しています(私の質問は他のデータベースにも同様に当てはまります)。私たちは、ユーザーがフィールドのほとんどすべての可能な組み合わせで検索できるWebインターフェースを持っています。

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

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

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

回答:


87

テーブルで発生する操作によって異なります。

SELECTがたくさんあり、変更がほとんどない場合は、好きなだけインデックスを作成してください。これにより、SELECTステートメントが(潜在的に)高速化されます。

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

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


1
明確にするために、2つの値のインデックスは、特定のケースでは意味がない場合があります。1つの値がめったに発生せず、それを調べたい場合です。つまり、値がどれほど一意であるかではなく、インデックスがどれほど選択的であるかということです。
charlie_pl 2017年

44

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

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

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


26

他の誰もがあなたに素晴らしいアドバイスを与えています。あなたが前進するにつれて、私はあなたに追加の提案をします。ある時点で、最適なインデックス作成戦略について決定を下す必要があります。しかし結局のところ、最良のPLANNEDインデックス作成戦略では、最終的には使用されないインデックスを作成してしまう可能性があります。使用されていないインデックスを見つける方法の1つは、インデックスの使用状況を監視することです。これは次のように行います。

alter index my_index_name monitoring usage;

その後、v $ object_usageをクエリすることで、その時点からインデックスが使用されているかどうかを監視できます。これに関する情報は、 『Oracle®Database Administrator's Guide』に記載されています。

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


14

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

これにはオーバーヘッドがありますが、データウェアハウスでは通常、行を1回だけ挿入しますが、更新することはありませんが、何千ものSELECTクエリに参加できるため、いずれかのインデックス作成から利益を得ることができます。列。

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

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

あなたの質問にもっと直接的に取り組むために、最初は明白なものにインデックスを付けるのはおそらく良いことだと思いますが、テーブルに対するクエリが役立つかどうかにインデックスを追加することを恐れないでください。


事実についてのそれの多く?私はあなたが次元を言おうとしていたと思いました。それはかなり奇妙なユースケースです。しかし、あなたはDBAとしてロックしているので、私は明らかに何かを逃していると言います。
ステファニーページ

@Stephanie、私たちは非常に同じシナリオを持っています.. Davidはそれらがビットマップインデックスであることを述べました。BITMAP JOINインデックスも使用します。はい、事実についてです。Oracleは、ビットマップインデックスに対して非常に効率的なAND操作を実行できます。たとえば、それぞれがビットマップインデックスを持つ5つの低カーディナリティ属性を持つWHERE句を持つことができます。実行プランを見ると、ビットマップAND操作(基本的には効率的なビットマップと操作)があり、実行プランを下に行くと、ビットマップがROWIDに変換されます。本当に速いです。
Tagar

12

単純化に関するEinsteinの言い換えでは、必要なだけ多くのインデックスを追加してください。

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

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

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


1
再評価に同意します。適切な管理は、「設定して忘れる」タスクではありません。ソフトウェアの変更。要件の変更。使用法が変わります。ある日導入された一見ささいな機能がすぐに最大のボトルネックになる可能性があり、昨日の要となるコードが休眠状態になり、リソースを消費するだけで無駄になってしまう可能性があります。反復的なアプローチにも同意します。一度にたくさんしすぎると、何がうまくいったかわかりません。
デュレット2016年

6

コストベースオプティマイザーは、SQLステートメントのプランを作成するときに、考慮すべき組み合わせが多いためにインデックスが多くなると、コストが発生します。バインド変数を正しく使用して、SQLステートメントがSQLキャッシュに留まるようにすることで、これを減らすことができます。その後、Oracleはソフト解析を実行し、前回見つけたプランを再利用できます。

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

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


私は賛成票を投じましたが...興味深く、学術的である一方で、余分な解析時間はあります。正しい数のインデックスの選択に影響を与えることは決してありません。同意する?
ステファニーページ

@StephaniePage私は何かを証明する実験をしていません。しかし、すべての列に単純に単一列のインデックスを作成するプロジェクトを見ました。一部のテーブルに80列ある場合、影響が出始めると思います。Oracleは、各インデックスによるアクセスのコストを考慮しているようです。しかし、はい、私は同意します。これよりも考慮すべき重要な点があります。
WW。

うーん...私はOracleがハード解析に費やす最大時間があると思います...いくつかのテーブル、たとえば7または8を超えるSQLを考えてみてくださいアクセスパス。
ステファニーページ

6

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

しかし、ここで引用しておいたほうがよいと思います。

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

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

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


これはすべての詳細なしに予言として取られるべきではありません。特に、1つのアクションから別のアクションへのパフォーマンスのゲイン/ロスを乗算できないためです。基本は同じままです。インデックスを追加すると、インデックスの再作成のため、挿入は最終的に遅くなります。
SovietFrontier

3

最終的に必要なインデックスの数は、データベースサーバー上で動作するアプリケーションの動作によって異なります。

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

アプリケーションが適切な量の読み取りを行っている場合、またはさらにそれがほぼすべての読み取りである場合、ほとんどのコストでパフォーマンスが大幅に向上するため、インデックスが適しています。


3

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

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

インデックス作成だけでなく、計算された検索フィールドやテーブルの分割などを含むようにDBを再構成します。これは、実際に負荷の形状とクエリパラメーター、クエリで「実際に」返す必要があるデータの量/量によって異なります。

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

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


3

これは実際には、実際的というより理論的な質問です。インデックスがパフォーマンスに与える影響は、使用しているハードウェア、Oracleのバージョン、インデックスのタイプなどによって異なります。昨日、OracleがHP製の専用ストレージを発表したと聞きました。あなたの場合については、いくつかの解決策が考えられます:1.大量のインデックス(> 20)を用意し、毎日(毎晩)再構築します。これは、テーブルが毎日何千もの更新/削除を取得する場合に特に役立ちます。2.テーブルをパーティション分割します(データモデルを適用する場合)。3.新しい/更新されたデータ用に別のテーブルを使用し、データを結合する夜間プロセスを実行します。これには、アプリケーションロジックの変更が必要です。4.データがこれをサポートしている場合は、IOT(索引構成表)に切り替えます。

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


インデックスの再構築がどのように役立つか、またはIOTがどのように役立つかわかりません。
David Aldridge

IOT-新しいユーザー定義のデータ型が使用されるようにアプリケーションを再設計できる場合、IOTはテーブルのインデックス作成に関するオーバーヘッドを節約します。ここではそうではないかもしれません。それは本当に依存します。インデックスの再構築-インデックスが多数あり、新しいデータにインデックスが作成されていない場合。
モシェ

IOTは引き続きインデックス構造であり、通常のインデックスよりもブロック分割のオーバーヘッドが多くなります。「インデックスの再構築-多くのインデックスがあり、新しいデータがインデックス付けされていない場合」...どのRDBMSが新しいエントリのインデックスを自動的に維持しないのですか?
David Aldridge

デビッド-もちろんです。これをSQL Serverのフルテキスト検索にインデックスを付ける機能(需要によってのみ)と組み合わせました。オラクルがそれを持っていることを望みます。他の2つの提案に固執することをお勧めします。
Moshe

2

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


2

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


2

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

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

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

インデックスを格納するために必要なスペースのコストもありますが、あなたの状況ではそれは問題ではないと述べました。ディスク領域がどれほど安価になったかを考えると、ほとんどの状況で同じことが当てはまります。


1

列はいくつありますか?私は常に、複数列のインデックスではなく、単一列のインデックスを作成するように言われてきました。つまり、列の数よりも多くのインデックスはありません。


1

本当に重要なのは、更新されるよりもはるかに頻繁に使用されることがわかっている場合(そして、これは使用統計を収集することを意味します)でない限り、インデックスを追加しないでください。

その基準を満たさないインデックスを使用すると、奇数の場合にインデックスが使用されないというパフォーマンス上のペナルティよりも、再構築のコストが高くなります。


1

SQLサーバーには、実際に使用されているインデックスを確認できる優れたツールがいくつか用意されています。この記事(http://www.mssqltips.com/tip.asp?tip=1239)には、更新の量ではなく、使用されている量の詳細を把握できるクエリがいくつかあります。


0

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


2
デッドロックを回避するための外部キー列のインデックス?なぜ、どのようにそうであるかを説明するリファレンスがありますか?
Jay Sullivan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.