インデックスは通常迅速に特定のカラム値の行を検索するのに使用されます。インデックスがない場合、関連する行を検索する場合 MySQL は最初の行から始め全テーブルを読まなければなりません。テーブルが大きいほど、コストがかかります。検索しているカラムのインデックスをテーブルが含んでいる場合、MySQL はすべてのデータを検索せずに、データファイルの途中でシークポジションを迅速に決定します。テーブルに 1000 行ある場合、連続して読む場合よりも少なくとも 100 倍の速度で処理が行われます。行のほとんどにアクセスしなければならない場合、連続して読むほうがより高速です。というのも、これはディスクシークの最小化が行われるためです。
ほとんどの MySQL インデックスは
(PRIMARY
KEY
、UNIQUE
、INDEX
、そして
FULLTEXT
) は B-trees
に保存されています。R-trees
を使用する空間データ型インデックスは例外で、MEMORY
テーブルでもハッシュインデックスがサポートされています。
文字列の接頭辞とエンドスペースは自動的に圧縮されます。項8.1.13. 「CREATE INDEX
構文」
を参照してください。
一般的に、インデックスは次のように使用されます。ハッシュインデックスの特徴は
(MEMORY
テーブルで使用される)
この節の終わりに説明されています。
MySQL はこれらの演算についてインデックスを使用します。
WHERE
節にマッチする行を迅速に検索する場合。
行を考慮に入れない場合。複数のインデックス間を選択できる場合、MySQL は通常最小行数を検索するインデックスを使用します。
結合実行時に、ほかのテーブルから行を取得する場合。同じ型とサイズでカラムを宣言すると、MySQL
でカラムのインデックスを効率的に使用できます。この例では、同じサイズで宣言されていれば
VARCHAR
と
CHAR
は同じと見なされます。たとえば、VARCHAR(10)
と CHAR(10)
は同じサイズですが、VARCHAR(10)
と CHAR(15)
は異なります。
異なるカラムを比較する場合、変換なしで値を直接比較できないときは、インデックスを使用できないことがあります。数値カラムを文字列カラムと比較する場合を考えます。数値カラムの値がたとえば
1
のとき、これは文字列カラムのいくつもの値
('1'
、' 1'
、'00001'
、'01.e1'
など)
に等しいと見なされる可能性があります。このため、文字列カラムにはどのようなインデックスも使用できません。
特定のインデックス化されたカラム
key_col
に対して、MIN()
あるいは
MAX()
値を検索する場合。これはインデックス内で
key_col
より前に発生するすべてのキーパートで、WHERE
が使用されているかを確認するプリプロセッサによって最適化されます。この場合
MySQL は
key_part_N
=
constant
MIN()
または
MAX()
表現それぞれに対して単一キールックアップを行い、定数で置き換えます。すべての表現が定数で置き換えられた場合、クエリーは一度に返されます。例
:
SELECT MIN(key_part2
),MAX(key_part2
) FROMtbl_name
WHEREkey_part1
=10;
使用可能キーのもっとも左側の接頭辞でソートやグループ分けが行われる際、テーブルをソートまたはグループ分けする場合に使用します
(たとえば、ORDER BY
)。すべてのキーパートに
key_part1
,
key_part2
DESC
が後続する場合、キーは逆の順序で読まれます。項4.2.13. 「ORDER BY
最適化」、項4.2.14. 「GROUP BY
最適化」
を参照してください。
データ行を参照せず値を取得するためにクエリーが最適化される場合もあります。クエリーがあるキーのもっとも左側の接頭辞を形成し、かつテーブル内で数値のみのカラムを使用する場合、選択された値は高速化を図るため、インデックスツリーから取得されることもあります。
SELECTkey_part3
FROMtbl_name
WHEREkey_part1
=1
たとえば次の
SELECT
ステートメントを発行したとします。
mysql> SELECT * FROM tbl_name
WHERE col1=val1
AND col2=val2
;
col1
と
col2
上で複合カラムインデックスが存在する場合、適当な行は直接取得されます。col1
と col2
に別々のシングルカラムインデックスが存在する場合、オプティマイザはインデックス結合最適化
(項4.2.6. 「インデックス結合最適化」を参照)
の使用を試みます。または、どのインデックスがより少ない行を検索できるかを決定し、そのインデックスを使用して行を取得することで、もっとも制限力のあるインデックスを検索しようとします。
テーブルに複合インデックスがある場合、オプティマイザではインデックスの左端の先頭部分のいずれかをレコードの検索に使用できます。たとえば、(col1,
col2, col3)
に 3
カラムのインデックスがある場合、(col1)
、(col1,
col2)
そして (col1, col2,
col3)
に対して、インデックスの検索機能を使用できます。
カラムがインデックスの左端の接頭辞を構成していない場合、MySQL
では、インデックスを使用できなくなります。次の
SELECT
ステートメントがあります。
SELECT * FROMtbl_name
WHERE col1=val1
; SELECT * FROMtbl_name
WHERE col1=val1
AND col2=val2
; SELECT * FROMtbl_name
WHERE col2=val2
; SELECT * FROMtbl_name
WHERE col2=val2
AND col3=val3
;
インデックスが (col1, col2,
col3)
に存在する場合、最初のクエリーだけがインデックスを使用できます。3
つめと 4
つめのクエリーには、インデックス化したカラムが必要ですが、(col2)
と (col2, col3)
は
(col1, col2, col3)
の左端の接頭辞ではありません。
=
,
>
,
>=
、<
,
<=
あるいは
BETWEEN
演算子を使用する表現のカラム比較に、B-tree
インデックスが使用可能です。LIKE
がワイルドカードキャラクタで始まらない定数文字列の場合、インデックスは
LIKE
比較にも使用できます。たとえば、次の
SELECT
ステートメントはインデックスを使用します。
SELECT * FROMtbl_name
WHEREkey_col
LIKE 'Patrick%'; SELECT * FROMtbl_name
WHEREkey_col
LIKE 'Pat%_ck%';
最初のステートメントでは、'Patrick'
<=
を含む行のみ考慮されます。2
つめのステートメントでは、key_col
<
'Patricl''Pat'
<=
を含む行のみ考慮されます。
key_col
<
'Pau'
次の SELECT
ステートメントはインデックスを使用しません。
SELECT * FROMtbl_name
WHEREkey_col
LIKE '%Patrick%'; SELECT * FROMtbl_name
WHEREkey_col
LIKEother_col
;
最初のステートメントでは、LIKE
値はワイルドカードキャラクタで始まります。2
つめのステートメントでは、LIKE
値は定数ではありません。
もし... LIKE
'%
そして文字列
%'文字列
は
3 文字より長い場合、MySQL はTurbo
Boyer-Moore
アルゴリズムを使用して、文字列のパターンを初期化してから、このパターンを使用して検索をすばやく実行します。
を使用した検索では、col_name
IS
NULLcol_name
にインデックスが張られている場合にインデックスが使用されます。
WHERE
節内のすべての AND
にかかっていないインデックスは、クエリーの最適化に使用されません。言い換えると、インデックスの使用を可能にするには、インデックスの先頭部分がすべての
AND
グループで使用されている必要があります。
次の WHERE
節ではインデックスが使用されます。
... WHEREindex_part1
=1 ANDindex_part2
=2 ANDother_column
=3 /*index
= 1 ORindex
= 2 */ ... WHEREindex
=1 OR A=10 ANDindex
=2 /* optimized like "index_part1
='hello'" */ ... WHEREindex_part1
='hello' ANDindex_part3
=5 /* Can use index onindex1
but not onindex2
orindex3
*/ ... WHEREindex1
=1 ANDindex2
=2 ORindex1
=3 ANDindex3
=3;
次の WHERE
節ではインデックスが使用されません。
/*index_part1
is not used */ ... WHEREindex_part2
=1 ANDindex_part3
=2 /* Index is not used in both parts of the WHERE clause */ ... WHEREindex
=1 OR A=10 /* No index spans all rows */ ... WHEREindex_part1
=1 ORindex_part2
=10
MySQL
では利用可能な場合でもインデックスが使用されない場合があることに注意してください。この一例として、インデックスの使用によって
MySQL
がテーブルの大部分のレコードにアクセスする必要が生じるとオプティマイザで推定される場合が挙げられます。(この場合は、必要なシークが減少するため、テーブルスキャンのほうが高速になる可能性が高くなります。)
ただしこのクエリーに、レコードの一部のみを取り出す
LIMIT
が使用されている場合、結果で返される少数のレコードを迅速に検索できるため、MySQL
はインデックスを使用します。
ハッシュインデックスは先ほど挙げたインデックスとは特徴が異なります。
=
or
<=>
演算子を使用する等価比較にのみ使用されます。<
のように値の範囲を検索する比較演算子には使用されません。
オプティマイザは ORDER
BY
オペレーション速度を上げるためにハッシュインデックスを使用することはできません。(このようなインデックスは順序どおりに次のエントリーを検索することはできません)
MySQL は 2
つの値の間にある行の数を判別することはできません。(どのインデックスを使用するかを決定する上、範囲オプティマイザによって使用されます)MyISAM
テーブルをハッシュインデックスを含む
MEMORY
テーブルに変換した場合、これは一部のクエリーに影響を与えるかもしれません。
行の検索には自然キーのみが使用できます。(B-tree インデックスでは、どのキーの左端の先頭部を使用しても行を検索できます)。