インデックスは、カラムが特定の値をもつレコードの迅速な検索に使用されます。インデックスがないと、MySQL がレコードを見つけるために、最初のレコードから開始し、テーブル全体を読み取るとが必要になります。テーブルが大きくなると、これにコストがかかります。クエリ対象のカラムにインデックスがあると、MySQL は全てのデータを探すことなく、データファイルの途中にあるシーク対象ポジションを迅速に取得することができます。テーブルに 1000 レコードある場合、シーケンシャルに読み取る場合と比較して少なくとも 100 倍は高速化できます。1000 レコードのほとんどすべてにアクセスする必要がある場合は、ディスクシークが最小になるため、シーケンシャルに読むほうが速くなることに注意してください。
MySQL インデックスのすべて(PRIMARY
KEY
、UNIQUE
、および
INDEX
)は、B
ツリーに格納されます。文字列の頭にある空白と最後にある空白は自動的に圧縮されます。
See 項6.5.7. 「CREATE INDEX
構文」。
インデックスの用途は以下のとおりです。
WHERE
節の条件に一致するレコードを迅速に検索する。
結合実行時に他のテーブルのレコードを取り出す。
インデックス化された特定のカラムの
MAX()
値や MIN()
値を検索する。これは、WHERE
key_part_# = すべてのキー部分の定数 < N
を使用しているかどうかをチェックするプリプロセッサによって最適化される。この場合、MySQL
では単一キーのルックアップを実行し、MIN()
式を定数に置換する。すべての式が定数に置換されると、ただちにクエリの応答が返される。
SELECT MIN(key_part2),MAX(key_part2) FROM table_name WHERE key_part1=10
使用可能キーの左端の先頭部分でソートやグループ化が実行されている場合、テーブルのソートやグループ化を実行する(例:
ORDER BY key_part_1,key_part_2
)。すべてのキー部分の後ろに
DESC
がある場合は、キーが逆の順序で読み取られる。
See 項5.2.8. 「MySQL による ORDER BY
の最適化」。
状況によっては、データファイルを参照せずに値を取り出すようにクエリを最適化できる。あるテーブルで使用カラムのすべてが数値型で、キーの左端の先頭部分を構成している場合は、インデックスツリーから非常に高速に値を取り出すことができる。
SELECT key_part3 FROM table_name WHERE key_part1=1
次の SELECT
ステートメントを指定したとします。
mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
col1
と col2
に複合インデックスが存在する場合、対応するレコードを直接読み取れます。col1
と col2
に独立した単一カラムインデックスが存在する場合、検索されるレコードの少ないインデックスを判定し、そのインデックスをレコードの読み取りに使用して、最も制限性の高いインデックスの検索が試行されます。
テーブルに複合インデックスがある場合、オプティマイザではインデックスの左端の先頭部分のいずれかをレコードの検索に使用できます。たとえば、(col1,
col2, col3)
に 3
カラムのインデックスがある場合、(col1)
、(col1,
col2)
、および (col1, col2,
col3)
に対して、インデックスの検索機能を使用できます。
カラムがインデックスの左端の先頭部分を構成していない場合、MySQL
では、部分インデックスを使用できなくなります。以下の
SELECT
ステートメントがあるとします。
mysql>SELECT * FROM tbl_name WHERE col1=val1;
mysql>SELECT * FROM tbl_name WHERE col2=val2;
mysql>SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
インデックスが (col1, col2, col3)
に存在する場合、最初のクエリだけがインデックスを使用できます。2
つめと 3
つめのクエリには、インデックス化したカラムが必要ですが、(col2)
と (col2, col3)
は (col1, col2,
col3)
の左端のプリフィックスではありません
MySQL は、LIKE
の引数がワイルドカード文字で始まらない文字列定数である場合に、LIKE
比較にもインデックスを使用します。たとえば、以下の
SELECT
ステートメントではインデックスが使用されます。
mysql>SELECT * FROM tbl_name WHERE key_col LIKE "Patrick%";
mysql>SELECT * FROM tbl_name WHERE key_col LIKE "Pat%_ck%";
最初のステートメントでは "Patrick" <=
key_col < "Patricl"
のあるレコードだけが考慮されます。2
つめのステートメントでは "Pat" <=
key_col < "Pau"
のあるレコードだけが考慮されます。
以下の SELECT
ステートメントではインデックスが使用されません。
mysql>SELECT * FROM tbl_name WHERE key_col LIKE "%Patrick%";
mysql>SELECT * FROM tbl_name WHERE key_col LIKE other_col;
最初のステートメントでは LIKE
がワイルドカード文字で始まっています。2
つめのステートメントでは LIKE
値が定数ではありません。
MySQL 4.0 ではこれ以外の LIKE
の最適化も実行されます。... LIKE
"%string%"
を使用し、string
が 3 文字より長い場合、MySQL は Turbo
Boyer-Moore
アルゴリズムを使用して、文字列のパターンを初期化してから、このパターンを使用して検索を素早く実行します。
column_name IS NULL
を使用した検索では、column_name
にインデックスが張られている場合にインデックスが使用されます。
通常 MySQL
は、検索するレコードを少なくするために、インデックスを使用します。インデックスは、以下の演算子で比較するカラムに使用されます。
=
、>
、>=
、<
、<=
、BETWEEN
、または、'something%'
などのワイルドカード以外のプリフィックスで始まるパターンに対する
LIKE
。
WHERE
節内の全ての
AND
にかかっていないインデックスは、クエリの最適化に使用されません。言い換えると、インデックスの使用を可能にするには、インデックスの先頭部分がすべての
AND
グループで使用されている必要があります。
次の WHERE
節ではインデックスが使用されます。
... WHERE index_part1=1 AND index_part2=2 AND other_column=3 ... WHERE index=1 OR A=10 AND index=2 /* index = 1 OR index = 2 */ ... WHERE index_part1='hello' AND index_part_3=5 /* optimized like "index_part1='hello'" */ ... WHERE index1=1 AND index2=2 OR index1=3 AND index3=3; /* Can use index on index1 but not on index2 or index 3 */
次の WHERE
節ではインデックスが使用されません。
... WHERE index_part2=1 AND index_part3=2 /* index_part_1 is not used */ ... WHERE index=1 OR A=10 /* Index is not used in both AND parts */ ... WHERE index_part1=1 OR index_part2=10 /* No index spans all rows */
MySQL
では利用可能な場合でもインデックスが使用されない場合があることに注意してください。この一例として、インデックスの使用によって、MySQL
がテーブルの 30%
を超えるレコードにアクセスする必要が生じる場合が挙げられます(この場合は、必要なシークが大幅に減少するため、テーブルスキャンのほうが高速になる可能性が高くなります)。
ただしこのクエリに、レコードの一部のみを取り出す
LIMIT
が使用されている場合、結果で返される少数のレコードを迅速に検索できるため、MySQL
はインデックスを使用します。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.