web-dev-qa-db-ja.com

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

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

それは話題外です、私は知っています、しかし、これを私に詳細に説明することができる誰かがいるならば、私は非常に、非常に感謝するでしょう。

373
good_evening

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

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

もちろん、インデックスがどれほど役に立つかは、多くのことによりますが、上のような類似のものを使ったいくつかの例があります。

  • あなたがデータベースに関する本を持っていて、そして単語「データベース」を索引付けしたなら、あなたはそれがページ1-59、61-290、および292から400で言及されているのを見るでしょう。そのような場合、索引はあまり役に立ちませんページを1つずつ見ていくと速くなります(データベースでは、これは「選択性の低さ」です)。
  • 10ページの本の場合、5ページのインデックスが前に付いた10ページの本になる可能性があるため、インデックスを作成するのは意味がありません。10ページをスキャンしてそれを実行するだけです。 。
  • インデックスはまた有用である必要があります - 一般的にインデックスを付ける意味がありません。 1ページあたりの文字 "L"の頻度.
479
Piskvor

最初に知っておかなければならないことは、インデックスはあなたが探している結果を得るために全テーブルをスキャンすることを避ける方法であるということです。

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

InnoDBとB +ツリーインデックス

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

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

したがって、次の表が与えられます。

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. たぶん、プロセスに追加のステップを追加することはそれを遅くしないで速くします。それは2つのステップに分割することによってSELECTを最適化することができ、最初に作成されたインメモリテーブルに値を格納し、次にこの2番目のテーブルでより重いクエリを実行することができます。

MySQLには他のインデックスもありますが、私はB + Treeのものがこれまでで最も使用されており、ハッシュのものが知っておくと良いことだと思いますが、他のものは MySQLドキュメントにあります。 .

"High Performance MySQL"という本を読むことを強くお勧めします。上記の答えは、インデックスに関する章に確実に基づいていました。

240
clarete

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

1:リストの真ん中に移動 - 探しているものより高いか低いか

2:上の場合は中と下の中間点に、下の場合は中と上

3:高いか低いかまた中点にジャンプするなど.

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

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

34
Joshua

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

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

ここで は私が見たことのあるインデックスの最も良い説明の1つです。残念ながら、これはSQL Server用であり、MySQL用ではありません。私はこの2つがどれほど似ているかわからない….

4
Abe Miessler

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

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

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

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

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

テーブルに簡単なインデックスを作成できます。単純なインデックスを作成するには、クエリからUNIQUEキーワードを省略するだけです。単純索引では、表内に重複値を入れることができます。

列内の値を降順で索引付けしたい場合は、列名の後に予約語DESCを追加できます。

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

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


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

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

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

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

0
WoodrowShigeru

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

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

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

0
sendon1982

回答のリストに視覚的な表現を追加します。 enter image description here

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

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

ソース: link

0
Anurag Sharma