MySQLのインデックスは非常に複雑な獣です。過去にMySQLインデックスについて説明しましたが、これまで深く掘り下げたことはありません。これらの一連のブログ投稿でこれを行います。このブログ投稿は、インデックスの非常に一般的なガイドとして機能するはずですが、これらのシリーズの他の部分では、これらの主題についてもう少し深く掘り下げます。
インデックスとは何ですか?
一般に、インデックスに関する以前のブログ投稿ですでに述べたように、インデックスは、それらが言及されているページへの参照を含むレコードのアルファベット順のリストです。 MySQLでは、インデックスは行をすばやく見つけるために最も一般的に使用されるデータ構造です。 「キー」という用語も聞こえるかもしれません。これはインデックスも指します。
インデックスは何をしますか?
MySQLでは、インデックスを使用して、特定の列値を持つ行をすばやく検索し、テーブル全体を読み取ってクエリに関連する行を検索しないようにします。インデックスは主に、データベースシステム(MySQLなど)に格納されているデータが大きくなる場合に使用されます。これは、テーブルが大きいほど、インデックスの恩恵を受ける可能性が高くなるためです。
MySQLインデックスタイプ
MySQLに関する限り、複数のタイプのインデックスがあることを聞いたことがあるかもしれません:
-
Bツリーインデックス-このようなインデックスは、WHERE句に一致するSELECTクエリを高速化するために頻繁に使用されます。このようなインデックスは、値が一意である必要がないフィールドで使用でき、NULL値も受け入れます。
-
フルテキストインデックス-このようなインデックスは、フルテキスト検索機能を使用するために使用されます。このタイプのインデックスは、値をインデックス内の値と直接比較するのではなく、テキスト内のキーワードを検索します。
-
テーブルから重複する値を削除するために、一意のインデックスが頻繁に使用されます。行値の一意性を強制します。
-
主キーもインデックスです。これは、AUTO_INCREMENT属性を持つフィールドと一緒に頻繁に使用されます。このタイプのインデックスはNULL値を受け入れず、一度設定されると、PRIMARYKEYを持つ列の値は変更できません。
-
降順インデックスは、行を降順で格納するインデックスです。このタイプのインデックスはMySQL8.0で導入されました-クエリによって降順が要求された場合、MySQLはこのタイプのインデックスを使用します。
MySQLのインデックスに最適なデータ型を選択する
インデックスに関する限り、MySQLはさまざまなデータ型をサポートしており、一部のデータ型は特定の種類のインデックス(たとえば、FULLTEXT)と一緒に使用できないことにも注意する必要があります。インデックスはテキストベース(CHAR、VARCHAR、またはTEXT)列でのみ使用できます。他のデータ型では使用できません)。したがって、データベースデザインのインデックスを実際に選択する前に、使用するデータ型を決定してください。問題の列(格納するデータ型の種類を決定します:数値を格納しますか?文字列値?数値と文字列値の両方?など)、次に格納する値の範囲を決定します(データ型の範囲を増やすことは後で時間のかかる作業になる可能性があるため、超えないと思われるものを選択してください-単純なデータ型を使用することを選択することをお勧めします)、およびNULLを使用する予定がない場合列の値については、可能な限りフィールドをNOTNULLとして指定してください。 lumnにはインデックスが付けられているため、エントリごとに追加のバイトが必要です。
MySQLのインデックスに最適な文字セットと照合を選択する
データ型は別として、MySQLの各文字がスペースを占めることにも注意してください。たとえば、UTF-8文字はそれぞれ1〜4バイトかかる可能性があるため、たとえば255文字のインデックス作成を避け、特定の列に50文字または100文字のみを使用することをお勧めします。
MySQLでインデックスを使用することの利点と欠点
MySQLでインデックスを使用する主な利点は、WHERE句に一致する検索クエリのパフォーマンスが向上することです。MySQLはテーブル全体を読み取って行を検索しないため、インデックスはWHERE句に一致するSELECTクエリを高速化します。クエリに関連します。ただし、インデックスには独自の欠点があることに注意してください。主なものは次のとおりです。
-
インデックスはディスクスペースを消費します。
-
インデックスは、INSERT、UPDATE、およびDELETEクエリのパフォーマンスを低下させます-データが更新されるとき、インデックスは次のようにする必要があります一緒に更新されました。
-
MySQLは、複数のタイプのインデックスを同時に使用することからユーザーを保護しません。つまり、同じ列でPRIMARY KEY、INDEX、およびUNIQUEINDEXを使用できます。MySQLはそのような間違いからあなたを保護しません。
一部のクエリが遅くなっていると思われる場合は、ClusterControlの[クエリモニター]タブを確認することを検討してください。クエリモニターを有効にすると、特定のクエリが最後に表示された日時とその最大値を確認できます。テーブルに最適なインデックスを選択するのに役立つ平均実行時間。
使用する最適なインデックスを選択するには、MySQLの組み込みメカニズムを使用できます。たとえば、クエリの説明者であるEXPLAINクエリを使用できます。使用されているテーブル、パーティションがあるかどうか、使用できるインデックス、使用されているキー(インデックス)について説明します。また、クエリが返すインデックスの長さと行数も返します。
mysql> EXPLAIN SELECT * FROM demo_table WHERE demo_field = ‘demo’\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: demo_table
partitions: NULL
type: ref
possible_keys: demo_field
key: demo_field
key_len: 1022
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
この場合、データセットが通常よりも大きい場合にMySQLがデータを効率的に取得できるようにするために、インデックスが頻繁に使用されることに注意してください。テーブルが小さい場合は、インデックスを使用する必要はないかもしれませんが、テーブルがどんどん大きくなっていることがわかった場合は、インデックスの恩恵を受ける可能性があります。
ただし、特定のシナリオに使用するのに最適なインデックスを選択するには、インデックスがパフォーマンスの問題の主な原因になる可能性があることに注意してください。 MySQLがインデックスを効果的に使用するかどうかは、クエリの設計、使用中のインデックス、使用中のインデックスのタイプ、クエリ実行時のデータベースの負荷など、いくつかの要因に依存することに注意してください。他のもの。 MySQLでインデックスを使用する際に考慮すべき点がいくつかあります。
-
どのくらいのデータがありますか?おそらくそれのいくつかは冗長ですか?
-
どのクエリを使用しますか?クエリでLIKE句を使用しますか?注文はどうですか?
-
クエリのパフォーマンスを向上させるために、どのような種類のインデックスを使用する必要がありますか?
-
インデックスは大きいですか、小さいですか?列のサイズを小さくするために、列のプレフィックスにインデックスを使用する必要がありますか?
同じ列で複数のタイプのインデックス(Bツリーインデックス、UNIQUEインデックス、PRIMARY KEYなど)を使用することはおそらく避けるべきであることに注意してください。
インデックスを使用したクエリのパフォーマンスを向上させるには、クエリを確認する必要があります。EXPLAINステートメントがその助けになります。一般に、インデックスでクエリのパフォーマンスを向上させる場合に考慮すべき点がいくつかあります。
-
データベースに必要なものだけを尋ねます。ほとんどの場合、SELECT列を使用すると、SELECT *を使用するよりも高速になります(インデックスを使用しない場合も同様です)
-
正確な値を検索する場合は、Bツリーインデックスが適している可能性があります(例:SELECT * FROM demo_table WHERE some_field ='x')またはワイルドカードを使用して値を検索する場合(例:SELECT * FROM demo_table WHERE some_field LIKE'demo%'-この場合、先頭に何かを指定してLIKEクエリを使用すると良いよりも害がある-検索するテキストの前にパーセント記号が付いたLIKEクエリを使用しないでください-そうすれば、MySQLは行の値が何で始まるかわからないため、インデックスを使用しない可能性があります)-覚えておいてくださいBツリーインデックスは、等しい(=)、より大きい(>)、以上(> =)、より小さい(<)、以下を使用する式の列比較にも使用できます。 (<=)またはBETWEEN演算子。
-
フルテキストを使用している場合は、フルテキストインデックスが適している可能性があります(MATCH ... AGAINST( ))検索クエリ、またはデータベースがテキストベースの列のみを使用するように設計されている場合-FULLTEXTインデックスはTEXT、CHAR、またはVARCHAR列を使用できますが、他のタイプの列では使用できません。
-
大きなテーブルで追加のI/O読み取りを行わずにクエリを実行する場合は、カバーインデックスが役立つ場合があります。 。カバーするインデックスを作成するには、クエリで使用されるWHERE、GROUP BY、およびSELECT句をカバーします。
このブログシリーズの今後のパートでインデックスの種類をさらに詳しく調べますが、一般的に、SELECT * FROM demo_table WHERE some_field ='x' aB-treeINDEXのようなクエリを使用する場合MATCH()AGAINST()クエリを使用する場合は、おそらくFULLTEXTインデックスを調べる必要があります。テーブルの行の値が非常に長い場合は、列の一部のインデックスを調べる必要があります。
インデックスはいくつ必要ですか?
SELECTクエリのパフォーマンスを向上させるためにインデックスを使用したことがある場合は、おそらく自分自身に疑問を投げかけたことがあるでしょう。実際にいくつのインデックスが必要ですか。これを理解するには、次の点に注意する必要があります。
-
インデックスは通常、大量のデータで最も効果的です。
-
MySQLは、クエリ内のSELECTステートメントごとに1つのインデックスのみを使用します(サブクエリは個別のステートメントと見なされます)-use EXPLAINクエリを使用して、使用するクエリに最も効果的なインデックスを見つけます。
-
インデックスは、ディスク領域をあまり犠牲にすることなく、すべてのSELECTステートメントを十分に高速にする必要があります-「十分に高速」ただし、相対的なものであるため、実験する必要があります。
MySQLでインデックスを処理する場合、さまざまなエンジンを使用する場合(たとえば、InnoDBではなくMyISAMを使用する場合)、いくつかの種類の制限がある可能性があることにも注意してください。別のブログで詳しく説明しますが、いくつかのアイデアがあります:
-
MyISAMテーブルとInnoDBテーブルごとのインデックスの最大数は64で、両方のインデックスごとの列の最大数です。ストレージエンジンは16です。
-
InnoDBの最大キー長は3500バイトです。MyISAMの最大キー長は1000バイトです。
-
フルテキストインデックスには、特定のストレージエンジンに制限があります。たとえば、InnoDBフルテキストインデックスには36のストップワード、MyISAMがあります。ストップワードリストは、143個のストップワードで少し大きくなっています。 InnoDBはこれらのストップワードをinnodb_ft_server_stopword_table変数から取得し、MyISAMはこれらのストップワードをstorage / myisam/ft_static.cファイルから取得します。ファイル内にあるすべてのワードはストップワードとして扱われます。
-
MyISAMは、MySQL 5.6(MySQL 5.6)まで全文検索オプションをサポートする唯一のストレージエンジンでした。正確には4)は、MySQL5.6.4以降のInnoDBがフルテキストインデックスをサポートすることを意味します。 FULLTEXTインデックスが使用されている場合、値をインデックス内の値と直接比較するのではなく、テキスト内のキーワードを検索します。
-
インデックスはInnoDBにとって非常に重要な役割を果たします-InnoDBは行にアクセスするときに行をロックするため、行InnoDBアクセスにより、ロックを減らすことができます。
-
MySQLでは、同じ列で重複するインデックスを使用できます。
-
特定のストレージエンジンには、特定のデフォルトタイプのインデックスがあります(たとえば、MEMORYストレージエンジンの場合、デフォルトのインデックスタイプはハッシュです。 )
MySQLのインデックスに関するこのパートでは、このリレーショナルデータベース管理システムのインデックスに関連するいくつかの一般的なことを説明しました。今後のブログ投稿では、特定のストレージエンジンでのインデックスの使用など、MySQLでインデックスを使用するいくつかのより詳細なシナリオについて説明します。また、ClusterControlを使用してMySQLでパフォーマンス目標を達成する方法についても説明します。