テーブルに格納されているレコードを高速に取り出すための仕組み
以下のようなO(n)問題を抱えたクエリがあるとする。
SELECT * FROM users WHERE first_name = ‘Tom’
このクエリのパフォーマンスを上げるためには、以下のようにIndexを貼る。
ALTER TABLE users ADD INDEX (first_name)
データの作成・更新時には、同時にインデックスの追加・更新も行われるため、上記のようなデメリットが生じる。
ALTER TABLE users ADD INDEX (first_name)
容量の増加を抑えつつ、性能を向上させたい時に有効なパターン
最初の4バイトだけにインデックスを貼る例
ALTER TABLE users ADD INDEX (first_name(4))
ALTER TABLE users ADD INDEX (last_name, first_name)
MySQLでは、1つのクエリを実行する際、1テーブルについて1インデックスしか使用できないが、マルチインデックスを適用していれば、有効なインデックスがクエリ実行の際に選択される。
マルチカラムインデックスの先頭に指定するカラムはカーディナリティの高いものにしておくのが通常良い。
NULLを除いて値が重複して出現しなくなる。 レコードの作成・更新において、全ての値を調べて同じ値が既に存在しないことを確認する。 MySQLでは、ユニークキーを指定するとユニークインデックスも指定される。
ALTER TABLE users ADD UNIQUE (first_name)
EXPLAIN句でクエリの実行計画を確認。
EXPLAIN SELECT * FROM users WHERE first_name = ‘Tom’
以下の項目を確認
インデックスを検討したほうが良いかもしれない判断基準をリストアップ。 あくまで推測するための基準なので、EXPLAINでの計測をしたほうが良い。
以下に該当するインデックスがクラスタインデックスとなる。
クラスタインデックス以外のインデックスをセカンダリインデックスという。 セカンダリインデックスには主キーの値が含まれている。 EXPLAINで計測することが前提がだが、主キーの値が含まれているので、カバンリングインデックスを狙う際は複合インデックスに主キーを含めなくてもセカンダリインデックスだけでカバリングインデックスになる可能性を覚えておくと良いかも。 cf. 知って得するInnoDBセカンダリインデックス活用術!
クエリの実行結果に必要なすべてのカラムを含むインデックスのこと。
データファイルを読まず、インデックスだけでカバーできるので、検索が高速化される。
SELECT * FROM users WHERE amount * 2 > 10;
amountにインデックスを貼った場合、インデックスを活用するには演算子を避ける。amount自体がインデックスに保持されており、演算結果が保持されているわけではない。SQL関数についても同様。
SELECT * FROM users WHERE amount > 10/2;
SELECT * FROM users WHERE amount IS NULL;
IS NULLやIS NOT NULLは基本的にはインデックスが有効に活用されない(DBMSの仕様に依る)。
SELECT * FROM users WHERE amount <> 10;
否定形はインデックスを活用できない。ORについても同様。
SELECT * FROM users WHERE name = 'a%';
LIKEを使う場合は、B-Treeの性質に依るため前方一致のみインデックスが活用される。
SELECT * FROM users WHERE age = '10'
ageが数値型の場合に文字列から数値に暗黙的な型がされるとインデックスが活用されなくなる。