MySQLインデックスはどのように機能しますか?


402

MySQLのインデックスがどのように機能するかに本当に興味があります。具体的には、テーブル全体をスキャンせずに、要求されたデータをどのように返すことができますか?

トピック外ですが、詳しく説明してくれる人がいたら、とてもありがたいです。



これは非常に幅広い質問です。インデックスを使用しないクエリの特定の例があり、その理由がわからない場合は、それを投稿すれば、人々が助けになるでしょう。
Hammerite 2010

SELECT * FROM members WHERE id = '1'-では、なぜインデックスを使用するとより速く機能するのですか?ここでそのインデックスは何をしますか?
good_evening 2010

2
これは、特定のインデックス付きレコード(おそらく主キーで識別される)を検索するクエリのように見えます。インデックスは、メモリに格納され、対応するインデックス行を見ることができ、実際のデータが格納されている場所へのポインターが含まれているため、インデックスが高速になります。そのため、MySQLはテーブルをスキャンしなくても、テーブル内の正確な場所に移動できます。
Hammerite 2010

よろしくお願いします!
オービットのライトネスレース

回答:


513

基本的に、テーブルのインデックスは、本のインデックスのように機能します(その名前が由来しています)。

データベースに関する本があり、ストレージなどの情報を見つけたいとします。索引がない場合(目次などの他の援助がないと仮定)、トピックが見つかるまでページを1つずつ移動する必要があります(つまりfull table scan)。一方、インデックスにはキーワードのリストがあるため、インデックスを調べて、storage113〜120、231、および354ページに記載されていることを確認します。次に、検索せずに直接これらのページに移動できます(つまり、インデックス、やや高速)。

もちろん、インデックスがどの程度役立つかは、多くのことに依存します-いくつかの例では、上記の類義語を使用しています:

  • データベースに関する本があり、「データベース」という単語にインデックスを付けた場合、1〜59、61〜290、および292〜400ページで言及されていることがわかります。このような場合、インデックスはあまり役に立ちません。ページを1つずつすばやく移動する(データベースでは、これは「選択性が低い」)。
  • 10ページの本の場合、インデックスを作成しても意味がありません。5ページのインデックスが前に付いた10ページの本になる可能性があります。これはばかげています。10ページをスキャンするだけで完了です。 。
  • インデックスも有用である必要があります。たとえば、ページあたりの文字「L」の頻度など、インデックスを付ける意味は通常ありません。

3
あなたはそれが何であるかを説明しているのではなく、それが内部でどのように技術的に機能しているかではありません。
Tutu Kumari

@Tutu Kumari:質問の改訂を参照してください。また、現在の質問に合わせて回答を自由に変更してください(さまざまなエンジンとインデックスタイプに注意してください-たとえば、ここのドキュメントを参照してください:dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html
Piskvorは

259

最初に知っておく必要があるのは、インデックスは、テーブル全体をスキャンして、探している結果を得ることを回避する方法であることです。

インデックスにはさまざまな種類があり、それらはストレージレイヤーに実装されているため、それらの間に標準はなく、使用しているストレージエンジンにも依存します。

InnoDBとB + Treeインデックス

InnoDBの場合、最も一般的なインデックスタイプは、要素をソートされた順序で格納するB + Treeベースのインデックスです。また、インデックス付きの値を取得するために実際のテーブルにアクセスする必要がないため、クエリの戻りがより高速になります。

このインデックスタイプの「問題」は、インデックスを使用するために左端の値をクエリする必要があることです。したがって、インデックスにlast_nameとfirst_nameの2つの列がある場合、これらのフィールドをクエリする順序は非常に重要です。

したがって、次の表を考えると:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

このクエリはインデックスを利用します:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

しかし、次のものは

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

first_name最初に列をクエリしていて、それがインデックスの左端の列ではないためです。

この最後の例はさらに悪いです:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

これは、インデックスの右端のフィールドの右端を比較しているためです。

ハッシュインデックス

これは、残念なことに、メモリバックエンドのみがサポートする別のインデックスタイプです。非常に高速ですが、フルルックアップにのみ役立ちます。つまり><やのような操作には使用できませんLIKE

これはメモリバックエンドに対してのみ機能するため、おそらくあまり使用しません。私が今考えることができる主なケースは、別の選択からの結果のセットでメモリに一時テーブルを作成し、ハッシュインデックスを使用してこの一時テーブルで他の多くの選択を実行するケースです。

大きなVARCHARフィールドがある場合、別の列を作成して大きな値のハッシュを保存することにより、Bツリーを使用するときにハッシュインデックスの使用を「エミュレート」できます。あなたがフィールドにURLを保存していて、値が非常に大きいとしましょう。と呼ばれる整数フィールドを作成し、url_hash同様のハッシュ関数CRC32または他のハッシュ関数を使用して、挿入時にURLをハッシュすることもできます。そして、この値を照会する必要がある場合は、次のようなことができます。

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

上記の例の問題は、CRC32関数が非常に小さなハッシュを生成するため、ハッシュされた値で多くの衝突が発生することです。正確な値が必要な場合は、次の手順でこの問題を修正できます。

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

衝突数が多い場合でもハッシュを行う価値はあります。これは、繰り返されるハッシュに対して2番目の比較(文字列1)のみを実行するためです。

残念ながら、この手法を使用しても、urlフィールドを比較するにはテーブルをヒットする必要があります。

要約

最適化について話をしたいときは常に考慮すべきいくつかの事実:

  1. 整数比較は文字列比較よりもはるかに高速です。これは、のハッシュインデックスのエミュレーションに関する例で説明できますInnoDB

  2. おそらく、プロセスにステップを追加すると、プロセスが速くなるのではなく、遅くなるのではないでしょうか。これはSELECT、を2つのステップに分割し、最初の1つが新しく作成されたメモリ内テーブルに値を格納し、この2番目のテーブルでより重いクエリを実行することで、を最適化できるという事実によって説明できます。

MySQLにも他のインデックスがありますが、B + Treeインデックスはこれまでで最も使用されていると思います。ハッシュインデックスは知っておくと良いでしょうが、MySQLのドキュメントで他のインデックスを見つけることができます。

「High Performance MySQL」の本を読むことを強くお勧めします。上記の答えは間違いなくインデックスに関する章に基づいていました。


2
上記の場合、次のクエリが有利になりますか?1。SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Akshay Taru 2013

1
最初のクエリは、2番目のクエリはしません。EXPLAINを使用:dev.mysql.com/doc/refman/5.5/en/explain.html MySQLで2番目のクエリのインデックスを作成するには、FULLTEXT INDEXを使用する必要があります:dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
エミリオニコラス

5
あなたが127で1位の答えが256だったので、私はあなたに賛成票を投じました。
pbarney 2016年

これは私にとって新しい情報でした。「これらのフィールドをクエリする順序は非常に重要です。」ありがとう。
Khatri 2016年

1
3年後の@pbarneyは、それぞれ256と512に近くなります。これが、私がバイナリ単位の増加と呼んでいるものです。
nanocv

43

基本的にインデックスは、すべてのキーのマップであり、順番に並べ替えられています。リストを順番に並べると、すべてのキーをチェックする代わりに、次のようなことができます。

1:リストの中央に移動-探しているものよりも高いまたは低いですか?

2:高い場合は中央と下部の中間点に移動し、低い場合は中央と上部に移動します

3:高いですか、低いですか?再度中点などにジャンプ

そのロジックを使用すると、すべてのアイテムをチェックする代わりに、約7ステップでソートされたリスト内の要素を見つけることができます。

明らかに複雑さはありますが、それはあなたに基本的な考えを与えます。


29
これはバイナリサーチと呼ばれます。
ddlshack

おかげで、最後に、dbがインデックスでどのように機能するかだけでなく、なぜより高速であるかを説明する回答が得られました。
Gershon Herczeg 2013

実際のステップ数はデータに大きく依存します-固有の値の数と範囲全体の分布。7は100値の理論上の最大値です。ここでのステップ数を計算する方法の完全な議論はstackoverflow.com/questions/10571170/...
ジョシュア

最も一般的なMySQLインデックスはB +ツリーで、バイナリ検索と同様に機能しますが、まったく同じではありません。アルゴリズムの複雑さは同じですが、検索方法は異​​なります。en.wikipedia.org/wiki/B-treeを
Matt

4

このリンクを見てください:http : //dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

それらがどのように機能するかは、1つのSO投稿でカバーするには主題が広すぎる。

これは、私が見た索引の最も良い説明の1つです。残念ながら、これはMySQLサーバーではなくSQLサーバー用です。2つがどれほど似ているかわかりません...


2
素敵な記事。SQL Serverは知りませんが、基本的な動作は非常によく似ています。(メタノート:2番目のリンクされた記事でCSSスタイルを無効にすると、コンテンツが再表示されます)
Piskvorが建物を去りました

3

インデックス作成の詳細については、このビデオをご覧ください

単純なインデックス作成テーブルに一意のインデックスを作成できます。一意のインデックスは、2つの行が同じインデックス値を持つことはできないことを意味します。これは、テーブルにインデックスを作成するための構文です

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

1つ以上の列を使用してインデックスを作成できます。たとえば、tutorials_tbltutorial_author を使用してインデックスを作成できます。

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

テーブルに単純なインデックスを作成できます。クエリからUNIQUEキーワードを省略して、単純なインデックスを作成します。単純なインデックスでは、テーブル内の重複した値が許可されます。

列の値に降順でインデックスを付ける場合は、列名の後に予約語DESCを追加できます。

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

1
Stack Overflowへようこそ!あなたのすべての回答があなた自身のビデオにリンクしていることに気づきました。露骨な自己宣伝は認められませんのでご注意ください。
SLバース-モニカの復活2017

彼は自分の動画を宣伝したいと考えています。LOL
Ilyas karim

1

2セント追加したいのですが。私はデータベースのエキスパートにはほど遠いですが、最近このトピックについて少し読んでみました。ELI5を試してみるのに十分です。だから、ここでは素人の説明があります。


インデックスは、連想配列のような、テーブルのミニミラーのようなものだと理解しています。一致するキーを指定してフィードすると、1つの「コマンド」でその行にジャンプできます。

ただし、そのインデックス/配列がない場合、クエリインタープリターはforループを使用してすべての行を調べ、一致するかどうかを確認する必要があります(フルテーブルスキャン)。

インデックスを作成すると、コンテンツをより速く検索する「メリット」と引き換えに、(そのミニミラーの)追加のストレージの「メリット」があります。

(dbエンジンに応じて)主キー、外部キー、または一意のキーを作成すると、それぞれのインデックスも自動的に設定されることに注意してください。同じ原則が、基本的にこれらのキーが機能する理由と方法です。


1

回答のリストに視覚的な表現を追加します。 ここに画像の説明を入力してください

MySQLは追加の間接層を使用します。セカンダリインデックスレコードはプライマリインデックスレコードを指し、プライマリインデックス自体がディスク上の行の場所を保持します。行オフセットが変更された場合、更新する必要があるのは主インデックスのみです。

警告:ディスクのデータ構造は図では平らに見えますが、実際にはB +ツリーです。

ソース:リンク


1

MySQL InnoDBには、2種類のインデックスがあります。

  1. クラスタ化インデックスと呼ばれる主キー。インデックスキーワードは、実際のレコードデータとともにB + Treeリーフノードに格納されます。

  2. 非クラスター化インデックスであるセカンダリキー。これらのインデックスは、B +ツリーリーフノードに独自のインデックスキーワードとともに主キーのキーワードのみを格納します。したがって、セカンダリインデックスから検索する場合、最初にプライマリキーインデックスキーワードを見つけ、プライマリキーB +ツリーをスキャンして実際のデータレコードを見つけます。これにより、プライマリインデックス検索に比べてセカンダリインデックスが遅くなります。ただし、select列がすべてセカンダリインデックスにある場合は、プライマリインデックスB + Treeを再度検索する必要はありません。これはカバリングインデックスと呼ばれます。

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