MySQLのインデックスがどのように機能するかに本当に興味があります。具体的には、テーブル全体をスキャンせずに、要求されたデータをどのように返すことができますか?
トピック外ですが、詳しく説明してくれる人がいたら、とてもありがたいです。
SELECT * FROM members WHERE id = '1'
-では、なぜインデックスを使用するとより速く機能するのですか?ここでそのインデックスは何をしますか?
MySQLのインデックスがどのように機能するかに本当に興味があります。具体的には、テーブル全体をスキャンせずに、要求されたデータをどのように返すことができますか?
トピック外ですが、詳しく説明してくれる人がいたら、とてもありがたいです。
SELECT * FROM members WHERE id = '1'
-では、なぜインデックスを使用するとより速く機能するのですか?ここでそのインデックスは何をしますか?
回答:
基本的に、テーブルのインデックスは、本のインデックスのように機能します(その名前が由来しています)。
データベースに関する本があり、ストレージなどの情報を見つけたいとします。索引がない場合(目次などの他の援助がないと仮定)、トピックが見つかるまでページを1つずつ移動する必要があります(つまりfull table scan
)。一方、インデックスにはキーワードのリストがあるため、インデックスを調べて、storage
113〜120、231、および354ページに記載されていることを確認します。次に、検索せずに直接これらのページに移動できます(つまり、インデックス、やや高速)。
もちろん、インデックスがどの程度役立つかは、多くのことに依存します-いくつかの例では、上記の類義語を使用しています:
最初に知っておく必要があるのは、インデックスは、テーブル全体をスキャンして、探している結果を得ることを回避する方法であることです。
インデックスにはさまざまな種類があり、それらはストレージレイヤーに実装されているため、それらの間に標準はなく、使用しているストレージエンジンにも依存します。
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
フィールドを比較するにはテーブルをヒットする必要があります。
最適化について話をしたいときは常に考慮すべきいくつかの事実:
整数比較は文字列比較よりもはるかに高速です。これは、のハッシュインデックスのエミュレーションに関する例で説明できますInnoDB
。
おそらく、プロセスにステップを追加すると、プロセスが速くなるのではなく、遅くなるのではないでしょうか。これはSELECT
、を2つのステップに分割し、最初の1つが新しく作成されたメモリ内テーブルに値を格納し、この2番目のテーブルでより重いクエリを実行することで、を最適化できるという事実によって説明できます。
MySQLにも他のインデックスがありますが、B + Treeインデックスはこれまでで最も使用されていると思います。ハッシュインデックスは知っておくと良いでしょうが、MySQLのドキュメントで他のインデックスを見つけることができます。
「High Performance MySQL」の本を読むことを強くお勧めします。上記の答えは間違いなくインデックスに関する章に基づいていました。
SELECT last_name, first_name FROM person WHERE last_name= "Constantine"
2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
基本的にインデックスは、すべてのキーのマップであり、順番に並べ替えられています。リストを順番に並べると、すべてのキーをチェックする代わりに、次のようなことができます。
1:リストの中央に移動-探しているものよりも高いまたは低いですか?
2:高い場合は中央と下部の中間点に移動し、低い場合は中央と上部に移動します
3:高いですか、低いですか?再度中点などにジャンプ
そのロジックを使用すると、すべてのアイテムをチェックする代わりに、約7ステップでソートされたリスト内の要素を見つけることができます。
明らかに複雑さはありますが、それはあなたに基本的な考えを与えます。
このリンクを見てください:http : //dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
それらがどのように機能するかは、1つのSO投稿でカバーするには主題が広すぎる。
これは、私が見た索引の最も良い説明の1つです。残念ながら、これはMySQLサーバーではなくSQLサーバー用です。2つがどれほど似ているかわかりません...
インデックス作成の詳細については、このビデオをご覧ください
単純なインデックス作成テーブルに一意のインデックスを作成できます。一意のインデックスは、2つの行が同じインデックス値を持つことはできないことを意味します。これは、テーブルにインデックスを作成するための構文です
CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);
1つ以上の列を使用してインデックスを作成できます。たとえば、tutorials_tbl
tutorial_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)
2セント追加したいのですが。私はデータベースのエキスパートにはほど遠いですが、最近このトピックについて少し読んでみました。ELI5を試してみるのに十分です。だから、ここでは素人の説明があります。
インデックスは、連想配列のような、テーブルのミニミラーのようなものだと理解しています。一致するキーを指定してフィードすると、1つの「コマンド」でその行にジャンプできます。
ただし、そのインデックス/配列がない場合、クエリインタープリターはforループを使用してすべての行を調べ、一致するかどうかを確認する必要があります(フルテーブルスキャン)。
インデックスを作成すると、コンテンツをより速く検索する「メリット」と引き換えに、(そのミニミラーの)追加のストレージの「メリット」があります。
(dbエンジンに応じて)主キー、外部キー、または一意のキーを作成すると、それぞれのインデックスも自動的に設定されることに注意してください。同じ原則が、基本的にこれらのキーが機能する理由と方法です。
MySQL InnoDBには、2種類のインデックスがあります。
クラスタ化インデックスと呼ばれる主キー。インデックスキーワードは、実際のレコードデータとともにB + Treeリーフノードに格納されます。
非クラスター化インデックスであるセカンダリキー。これらのインデックスは、B +ツリーリーフノードに独自のインデックスキーワードとともに主キーのキーワードのみを格納します。したがって、セカンダリインデックスから検索する場合、最初にプライマリキーインデックスキーワードを見つけ、プライマリキーB +ツリーをスキャンして実際のデータレコードを見つけます。これにより、プライマリインデックス検索に比べてセカンダリインデックスが遅くなります。ただし、select
列がすべてセカンダリインデックスにある場合は、プライマリインデックスB + Treeを再度検索する必要はありません。これはカバリングインデックスと呼ばれます。