web-dev-qa-db-ja.com

MySQLインデックス-ベストプラクティスは何ですか?

私はしばらくの間MySQLデータベースでインデックスを使用していましたが、それらについては適切にlearnt使用しませんでした。一般に、WHERE句を使用して検索または選択するすべてのフィールドにインデックスを付けますが、白黒ではない場合があります。

MySQLインデックスのベストプラクティスは何ですか?

状況/ジレンマの例:

テーブルに6つの列があり、それらのすべてが検索可能な場合、すべての列にインデックスを付ける必要がありますか?

インデックス作成のパフォーマンスへの悪影響は何ですか?

サイトの一部から検索可能なVARCHAR 2500列がある場合、インデックスを作成する必要がありますか?

192
Haroldo

あなたは間違いなくインデックス作成に時間を費やす必要があります。それについてはたくさん書かれていますが、何が起こっているのかを理解することが重要です。

大まかに言って、インデックスはテーブルの行に順序付けを課します。

簡単にするために、テーブルが単なる大きなCSVファイルであるとします。行が挿入されるたびに、最後に挿入されます。したがって、表の「自然な」順序は、行が挿入された順序にすぎません。

そのCSVファイルが非常に初歩的なスプレッドシートアプリケーションに読み込まれているとします。このスプレッドシートは、データを表示し、行に順番に番号を付けます。

ここで、3番目の列に値「M」を持つすべての行を見つける必要があると想像してください。利用可能なものを考えると、選択肢は1つだけです。テーブルをスキャンして、各行の3列目の値を確認します。多くの行がある場合、この方法(「テーブルスキャン」)には時間がかかることがあります。

ここで、このテーブルに加えて、インデックスがあることを想像してください。この特定のインデックスは、3番目の列の値のインデックスです。インデックスは、3番目の列のすべての値を意味のある順序(アルファベット順など)でリストし、それぞれについて、その値が表示される行番号のリストを提供します。

これで、3番目の列の値が「M」であるすべての行を見つけるための優れた戦略ができました。たとえば、 バイナリ検索 !を実行できます。テーブルスキャンではN行(Nは行数)を調べる必要がありますが、バイナリ検索では、最悪の場合、log-nインデックスエントリを調べるだけで済みます。うわー、それははるかに簡単だと確信しています!

もちろん、このインデックスがあり、テーブルに行を追加する場合(概念テーブルの仕組みなので、最後に)、毎回インデックスを更新する必要があります。そのため、新しい行を作成している間にもう少し作業を行いますが、何かを検索するときの時間を大幅に節約できます。

そのため、一般に、インデックス作成は読み取り効率と書き込み効率のトレードオフを作成します。インデックスがない場合、挿入は非常に高速になります。データベースエンジンはテーブルに行を追加するだけです。インデックスを追加すると、エンジンは挿入の実行中に各インデックスを更新する必要があります。

一方、読み取りははるかに高速になります。

これが最初の2つの質問に当てはまることを願っています(他の人が答えたように、正しいバランスを見つける必要があります)。

3番目のシナリオはもう少し複雑です。 LIKEを使用している場合、インデックスエンジンは通常、最初の「%」までの読み取り速度に役立ちます。つまり、WHERE列のLIKE 'foo%bar%'を選択している場合、データベースはインデックスを使用して列が「foo」で始まるすべての行を検索し、その中間行セットをスキャンしてサブセットを見つける必要があります「バー」を含む。 SELECT ... WHERE列LIKE '%bar%'はインデックスを使用できません。理由がわかるといいのですが。

最後に、複数の列のインデックスについて考える必要があります。概念は同じで、LIKEのものと同じように動作します-基本的に、(a、b、c)にインデックスがある場合、エンジンは可能な限り左から右にインデックスを使用し続けます。そのため、列aの検索では、(a、b)のインデックスと同様に、(a、b、c)インデックスを使用する場合があります。ただし、WHERE b = 5 AND c = 1を検索する場合、エンジンは全表スキャンを実行する必要があります。

これが少し光を当てるのに役立つことを願っていますが、これらのことを詳しく説明している優れた記事を数時間掘り下げてみることをお勧めします。特定のデータベースサーバーのドキュメントを読むこともお勧めします。クエリプランナーがインデックスを実装および使用する方法は、かなり大きく異なります。

226
timdev

More of the Arting the Art of Indexing のようなプレゼンテーションをご覧ください。

アップデート12/2012:私は私の新しいプレゼンテーションを投稿しました: How to Design Indexes、Really 。これは、2012年10月にサンタクララのZendConで、2012年12月にPercona Live Londonで発表しました。

最適なインデックスの設計は、アプリで実行するクエリと一致する必要があるプロセスです。

インデックスを作成するのに最適なカラム、またはすべてのカラムにインデックスを付けるかどうか、カラムなし、複数のカラムにまたがるインデックスなどの汎用ルールを推奨することは困難です。実行する必要のあるクエリによって異なります。

はい、オーバーヘッドがありますので、不必要にインデックスを作成しないでください。ただし、shouldは、迅速に実行する必要があるクエリにメリットをもたらすインデックスを作成する必要があります。インデックスのオーバーヘッドは、通常、その利点をはるかに上回ります。

VARCHAR(2500)の列​​の場合、おそらく FULLTEXTインデックス またはプレフィックスインデックスを使用する必要があります。

CREATE INDEX i ON SomeTable(longVarchar(100));

その長いvarcharの途中にある単語を検索している場合、従来のインデックスは役に立たないことに注意してください。そのためには、フルテキストインデックスを使用します。

53
Bill Karwin

他の回答では良いアドバイスのいくつかを繰り返しませんが、追加します:

化合物指数

複合インデックス-複数の列を含むインデックスを作成できます。 MySQLはこれらをleftからrightまで使用できます。あなたが持っている場合:

Table A
Id
Name
Category
Age
Description

name/Category/Ageをこの順序で含む複合インデックスがある場合、これらのWHERE句はインデックスを使用します。

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

しかし

WHERE Category='A' and Age > 18

左から右にすべてを使用する必要があるため、そのインデックスを使用しません。

説明

Explain/Explain Extendedを使用して、MySQLで使用可能なインデックスと実際に選択するインデックスを理解します。 MySQLは、クエリごとにONEキーのみを使用します

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

スロークエリログ

低速クエリログ をオンにして、どのクエリが低速で実行されているかを確認します。

広い列

最初の数文字で区別のMOSTが発生する幅の広い列がある場合、インデックスの最初のN文字のみを使用できます。例:varchar(255)として定義されたReferenceNumber列がありますが、ケースの97%、参照番号は10文字以下です。最初の10文字のみを見るようにインデックスを変更し、パフォーマンスをかなり改善しました。

44
Eric J.

テーブルに6つの列があり、それらのすべてが検索可能な場合、すべての列にインデックスを付けるか、どれにもインデックスを付けないか

フィールドごとにフィールドを検索していますか、または複数のフィールドを使用して検索していますか?どのフィールドがmostで検索されていますか?フィールドタイプは何ですか? (たとえば、VARCHARの場合よりもINTの方がインデックスの動作が良好です)実行中のクエリでEXPLAINを使用しようとしましたか?

インデックス作成のパフォーマンスへの悪影響は何ですか

更新と挿入は遅くなります。余分なストレージスペースの要件もありますが、最近では重要ではありません。

サイトの一部から検索可能なVARCHAR 2500列がある場合、インデックスを作成する必要があります

いいえ、UNIQUE(既にインデックスが作成されていることを意味する)であるか、そのフィールドでexact一致のみを検索する(LIKEまたはmySQLの全文検索を使用しない)場合を除きます。

通常、WHERE句を使用して検索または選択するフィールドにインデックスを付けます

通常、最もクエリの多いフィールドにインデックスを付け、次にVARCHARSのフィールドではなくINT/BOOLEANs/ENUMにインデックスを付けます。多くの場合、個々のフィールドのインデックスではなく、結合されたフィールドのインデックスを作成する必要があることを忘れないでください。 EXPLAINを使用して、スローログを確認します。

20
Pete

データの効率的なロード:インデックスは検索を高速化しますが、挿入と削除、およびインデックス付き列の値の更新を遅くします。つまり、インデックスは書き込みを伴うほとんどの操作を遅くします。これは、行を書き込むにはデータ行だけでなくインデックスも変更する必要があるためです。テーブルのインデックスが多いほど、より多くの変更を行う必要があり、平均的なパフォーマンスの低下が大きくなります。ほとんどのテーブルは多数の読み取りと少数の書き込みを受け取りますが、書き込みの割合が高いテーブルの場合、インデックスの更新のコストは非常に大きくなる可能性があります。

インデックスを避ける:クエリのパフォーマンスを向上させるために特定のインデックスが必要ない場合は、作成しないでください。

ディスク領域:インデックスはディスク領域を占有し、複数のインデックスはそれに応じてより多くの領域を占有します。これにより、インデックスがない場合よりも早くテーブルサイズの制限に達する可能性があります。可能な限りインデックスを避けてください。

テイクアウト:インデックスをオーバーしないでください

11
Srikar Doddi

一般に、インデックスはデータベース検索の高速化に役立ち、余分なディスク領域を使用し、INSERT/UPDATE/DELETEクエリを遅くするというデメリットがあります。 EXPLAINを使用して結果を読み取り、MySQLがインデックスを使用するタイミングを確認します。

テーブルに6つの列があり、それらのすべてが検索可能な場合、すべての列にインデックスを付ける必要がありますか?

6列すべてにインデックスを付けることが常にベストプラクティスとは限りません。

(a)特定の情報を検索するときにこれらの列のいずれかを使用しますか?

(b)これらの列の選択度はどのくらいですか(テーブルのレコードの合計量と比較して、いくつの異なる値が格納されていますか)。

MySQLはコストベースのオプティマイザーを使用します。これは、クエリを実行するときに「最も安い」パスを見つけようとします。また、選択性の低いフィールドは適切な候補ではありません。

インデックス作成によるパフォーマンスへの悪影響は何ですか?

既に回答済み:追加のディスク領域、挿入時のパフォーマンスの低下-更新-削除。

サイトの一部から検索可能なVARCHAR 2500列がある場合、インデックスを作成する必要がありますか?

FULLTEXT Index を試してください。

5
Anax

1/2)インデックスは特定の選択操作を高速化しますが、挿入、更新、削除などの他の操作を遅くします。それは良いバランスになります。

3)全文索引またはおそらくスフィンクスを使用する

4
Paul Creasey