一般にどの列が適切なインデックスを作成しますか?


97

インデックスとは何ですか?インデックスを使用してデータベースのクエリを最適化するにはどうすればよいですか?」のフォローアップとして、インデックスについて学習しようとしているところ、どのカラムがインデックス候補として適していますか?特にMS SQLデータベースについては?

いくつかのグーグルの後、私が読んだすべては、一般的に増加し、一意である列が良いインデックスを作成することを示唆しています(MySQLのauto_incrementのようなもの)、私はこれを理解していますが、MS SQLを使用しており、主キーにGUIDを使用しているため、そのインデックスはGUID列にはメリットがありません...


「クックブック」はどうですか: mysql.rjweb.org/doc.php/index_cookbook_mysql
Rick James

回答:


109

インデックスは、クエリの最適化と、テーブルからの結果の迅速な検索に重要​​な役割を果たします。したがって、インデックスを作成する列を選択することが最も重要なステップです。インデックス作成を検討できる主要な場所は2つあります。WHERE句で参照される列とJOIN句で使用される列です。つまり、特定のレコードを検索する必要がある場合は、そのような列にインデックスを付ける必要があります。SELECTクエリが以下のようなインデックスを使用する、buyersという名前のテーブルがあるとします。

SELECT
 buyer_id /* no need to index */
FROM buyers
WHERE first_name='Tariq' /* consider to use index */
AND last_name='Iqbal'   /* consider to use index */

「buyer_id」はSELECT部分​​で参照されるため、MySQLは選択された行を制限するためにそれを使用しません。したがって、インデックスを作成する必要はあまりありません。以下は、上記とは少し異なる別の例です。

SELECT
 buyers.buyer_id, /* no need to index */
 country.name    /* no need to index */
FROM buyers LEFT JOIN country
ON buyers.country_id=country.country_id /* consider to use index */
WHERE
 first_name='Tariq' /* consider to use index */
AND
 last_name='Iqbal' /* consider to use index */

上記のクエリfirst_nameによると、last_name列はWHERE句にあるため、インデックスを付けることができます。また、JOIN句に含まれているため、countryテーブルの追加フィールドcountry_idをインデックス作成の対象とすることができます。したがって、WHERE句またはJOIN句のすべてのフィールドでインデックス作成を検討できます。

次のリストは、テーブルにインデックスを作成する場合に常に留意する必要があるいくつかのヒントも示しています。

  • WHERE句とORDER BY句で必要な列のみにインデックスを付けます。豊富な列のインデックスを作成すると、いくつかの欠点が生じます。
  • MySQLの「インデックスプレフィックス」または「マルチカラムインデックス」機能を利用してみてください。INDEX(first_name、last_name)などのインデックスを作成する場合は、INDEX(first_name)を作成しないでください。ただし、「インデックスプレフィックス」または「マルチカラムインデックス」は、すべての検索ケースで推奨されるわけではありません。
  • インデックス作成を検討する列にはNOT NULL属性を使用して、NULL値が格納されないようにします。
  • --log-long-formatオプションを使用して、インデックスを使用していないクエリをログに記録します。このようにして、このログファイルを調べ、それに応じてクエリを調整できます。
  • EXPLAINステートメントは、MySQLがクエリを実行する方法を明らかにするのに役立ちます。これは、テーブルが結合される方法と順序を示しています。これは、最適化されたクエリの記述方法や、列にインデックスを付ける必要があるかどうかを判断するのに非常に役立ちます。

アップデート(2015年2月23日):

インデックス(良好/不良)があると、挿入と更新の時間が長くなります。

インデックス(インデックスの数とタイプ)に応じて、結果が検索されます。インデックスが原因で検索時間が長くなる場合、それは悪いインデックスです。

どんな本でもそうであるように、「インデックスページ」は章の開始ページ、トピックページ番号の開始、サブトピックページの開始を含むことができます。インデックスページのいくつかの説明は役立ちますが、より詳細なインデックスはあなたを混乱させたり、怖がらせたりする可能性があります。インデックスにもメモリがあります。

インデックスの選択は賢明でなければなりません。すべての列がインデックスを必要とするわけではないことに注意してください。


おかげSomnath、だから、それはインデックスが唯一の我々が使用することを計画している列のために作成しなければならない意味しないWHEREJOINSまたはHAVING
ムハンマドババール2015

3
はい、WHERE、JOINS、またはHAVINGの使用を計画している列にはインデックスを使用してください。ただし、すべての条件列にインデックスは必要ありません。多くのクエリで他の条件列が使用されているため、条件列が1回だけ使用されるため、多くのクエリで使用されるため、その列へのインデックス付けを優先する場合があります。
Somnath Muluk、2015

1
回答は、TL; DRセクションに「WHERE句で参照される列とJOIN句で使用される列」を配置することで得られます。
jpmc26 2017年

つまり、私のWHERE句で、列が2つの値しか取り得ないフィールドの値をチェックしている場合、そのバイナリ列にインデックスを付ける必要があるということですか。これは間違っているようです。
AjaxLeung 2018

@AjaxLeung:Knuthの格言「時期尚早の最適化はすべての悪の根源です」を思い出してください。バイナリ列にインデックスを作成できますが、それはコスト(挿入、更新時間など)に依存する必要があります。ビジネスロジックがそのバイナリスイッチに依存することが多い場合、バイナリ列にインデックスを付ける必要がある場合があります。
Somnath Muluk

20

一部の人々はここで同様の質問に答えました:どのようにして良いインデックスが何であるかを知っていますか?

基本的に、それは実際にデータのクエリ方法に依存します。クエリに関連するデータセットの小さなサブセットをすばやく識別するインデックスが必要です。日付スタンプでクエリを実行しない場合は、ほとんど一意であっても、インデックスは必要ありません。特定の日付範囲で発生したイベントを取得するだけなら、間違いなく1つ必要です。ほとんどの場合、性別のインデックスは無意味です。ただし、すべての男性に関する統計を取得し、すべての女性について個別に統計を取得する場合は、作成する価値があります。クエリパターンが何であるかを理解し、どのパラメータにアクセスすると検索スペースが最も狭くなり、それが最良のインデックスです。

また、作成するインデックスの種類も考慮してください。Bツリーはほとんどの場合に適していて、範囲クエリを許可しますが、ハッシュインデックスを使用すると、目的を達成できます(ただし、範囲は許可されません)。他のタイプのインデックスには、他の長所と短所があります。

幸運を!


9

すべては、テーブルについてどのようなクエリを要求するかによって異なります。列Xに特定の値を持つすべての行を要求する場合、インデックスを使用できない場合は、テーブル全体をスキャンする必要があります。

インデックスは次の場合に役立ちます。

  • 1つまたは複数の列に高度な一意性がある
  • 列の特定の値または値の範囲を探す必要があることがよくあります。

次の場合は役に立ちません。

  • テーブルの行の大きな%(> 10-20%)を選択しています
  • 追加のスペース使用量が問題です
  • 挿入パフォーマンスを最大化したい。テーブルのすべてのインデックスは、データが変更されるたびに更新する必要があるため、挿入と更新のパフォーマンスが低下します。

主キー列は一意であり、行の検索によく使用されるため、通常、主キー列はインデックス作成に最適です。


値が文字列内のどこにでもある可能性がある文字列検索では、その場合、それらのインデックスを使用しない可能性があります。
Arthur Thomas

5

一般的に(私はmssqlを使用しないため、具体的にコメントすることはできません)、主キーは適切なインデックスを作成します。これらは一意であり、値を指定する必要があります。(また、主キーは非常に優れたインデックスを作成するため、通常は自動的に作成されるインデックスを持っています。)

インデックスは、バイナリ検索(線形検索よりもはるかに高速)を可能にするためにソートされた列のコピーです。データベースシステムは、特にデータが単純な数値よりも複雑である場合、さまざまなトリックを使用して検索をさらに高速化できます。

私の提案は、最初はインデックスを使用せず、クエリのプロファイルを作成することです。特定のクエリ(姓で人を検索するなど)が頻繁に実行される場合は、関連属性とプロファイルにインデックスを作成してみてください。クエリが著しく高速化され、挿入と更新の速度がほとんど低下しない場合は、インデックスを維持してください。

(申し訳ありませんが、他の質問で言及されていることを繰り返しているのであれば、私は以前に遭遇したことがありませんでした。)


5

テーブルからデータを抽出するために定期的に使用される列には、インデックスを付ける必要があります。

これには以下が含まれます:外部キー-

select * from tblOrder where status_id=:v_outstanding

説明フィールド-

select * from tblCust where Surname like "O'Brian%"

列は一意である必要はありません。実際、例外を検索するとき、バイナリインデックスから本当に良いパフォーマンスを得ることができます。

select * from tblOrder where paidYN='N'

外部キーについての明示的な言及は、結合を検討する上で本当に問題を解決しました。
pfabri

3

それは本当にあなたのクエリに依存します。たとえば、ほとんどテーブルに書き込むだけの場合は、インデックスを作成しないのが最善です。インデックスが遅くなるだけで、使用されることはありません。別のテーブルとの結合に使用している列は、インデックスの候補として適しています。

また、不足しているインデックス機能についてもお読みください。それはあなたのデータベースに対して使用されている実際のクエリを監視し、どのインデックスがパフォーマンスを改善したかを教えてくれます。


3

GUID列は、インデックス作成の最適な候補ではありません。インデックスは、意味のある順序、つまりソート(整数、日付など)を指定できるデータ型の列に最適です。

列のデータが一般に増加しているかどうかは関係ありません。列にインデックスを作成すると、そのインデックスは独自のデータ構造を作成し、格納された順序(非クラスター化インデックス)に関係なく、テーブル内の実際のアイテムを単に参照します。次に、たとえば、インデックスデータ構造に対してバイナリ検索を実行して、高速な検索を提供できます。

データを物理的に並べ替える「クラスター化インデックス」を作成することもできます。ただし、これらはテーブルごとに1つしか持つことができませんが、非クラスター化インデックスは複数持つことができます。


まあ、それはそのように完全に正確ではありません。GUID列に通常の非クラスター化インデックスを簡単に作成できます-なぜですか?GUIDをクラスタリングキーとして使用する場合(たとえば、CLUSTERED INDEXの場合)、GUIDには大きな欠点があります。GUIDは使用するのに不都合です。
marc_s 2009年

1

古い経験則は、WHERE、ORDER BY、およびGROUP BY句で頻繁に使用される列、または結合で頻繁に使用されると思われる列でした。主キーではなく、インデックスを参照していることに注意してください

「バニラっぽい」答えを出すのではなく、データへのアクセス方法に本当に依存します


1

主キーは常にインデックスである必要があります。(実際に、MS SQLによって自動的にインデックスが作成されなかった場合は、驚きます。)また、自分で、SELECTまたはORDER頻繁に列にインデックスを作成する必要があります。それらの目的は、単一の値の迅速な検索とより高速なソートの両方です。

too多くの列にインデックスを付ける際の唯一の本当の危険は、すべてのインデックスも更新する必要があるため、大きなテーブルの行への変更を遅くすることです。インデックスを付ける対象が本当にわからない場合は、最も遅いクエリの時間を計り、最も頻繁に使用されている列を調べ、インデックスを作成します。次に、それらがどれだけ速いかを確認します。


1

昇順または降順で並べられた数値データ型は、さまざまな理由から適切なインデックスです。まず、数値は通常、文字列(varchar、char、nvarcharなど)よりも評価が高速です。次に、値が順序付けされていない場合、インデックスを更新するために行やページをシャッフルする必要がある場合があります。これは追加のオーバーヘッドです。

SQL Server 2005を使用しており、uniqueidentifiers(GUID)を使用するように設定していて、ランダムな性質である必要がない場合は、連続したuniqueidentifierタイプを確認してください。

最後に、クラスター化インデックスについて話している場合は、物理データの種類について話していることになります。クラスター化インデックスとして文字列を使用している場合、醜くなる可能性があります。


0

GUIDを使用している場合は、さらに高速になります。レコードがあるとしましょう

  1. 100
  2. 200
  3. 3000
  4. ....

インデックス(バイナリ検索)がある場合、O(n)時間で順次検索するのではなく、O(lg n)時間で探しているレコードの物理的な場所を見つけることができます。これは、所有しているレコードがわからないためですあなたのテーブルに。


0

最適なインデックスは、テーブルの内容と達成しようとしていることによって異なります。

例として、メンバーの社会保障番号の主キーを持つメンバーデータベースを取り上げます。アプリケーションプライマリーはこの方法で個人を参照するため、SSを選択しますが、メンバーの姓名を使用する検索関数も作成する必要があります。次に、これら2つのフィールドにインデックスを作成することをお勧めします。

最初に、どのデータをクエリするかを調べてから、インデックスを作成する必要があるデータを決定する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.