この節では WHERE
節をプロセスする際の最適化方法を記述します。例では
SELECT
ステートメントを使用していますが、DELETE
および UPDATE
ステートメントの
WHERE
節にも同じ最適化が適用されます。
また、この節は完全なものではないため、注意が必要です。MySQL は多様な最適化を実行するため、すべてを文書化するには時間が足りませんでした。
MySQL によって実行される最適化の一部をここに紹介します
不要なかっこの削除。
((a AND b) AND c OR (((a AND b) AND (c AND d)))) -> (a AND b AND c) OR (a AND b AND c AND d)
定数の折りたたみ。
(a<b AND b=c) AND a=5 -> b>5 AND b=c AND a=5
定数条件の削除 (定数の折りたたみに必要)。
(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6) -> B=5 OR B=6
インデックスが使用する定数式が評価されるのは、1 回に限られる。
COUNT(*)
WHERE
がない単一テーブルの COUNT(*)
は、MyISAM
と
HEAP
テーブルのテーブル情報から直接取り出される。これは、テーブル
1 つのみで使用する場合はすべての
NOT NULL
式でも実行される。
無効定数式の早期検出。MySQL は実行不可能な
SELECT
ステートメントがある場合、それを迅速に検出し、結果としてレコードを返さない。
GROUP BY
またはグループ関数
(COUNT()
、MIN()
)
を使用しない場合、HAVING
は WHERE
とマージされる。
サブ結合のそれぞれに、単純な
WHERE
が構造化され、サブ結合ごとに迅速に
WHERE
評価を取得し、可能なかぎり迅速にレコードをスキップする。
クエリー内のほかのすべてのテーブルの前に、まず、すべての定数テーブルが読み込まれる。定数テーブルとは次のものを指す。
空白テーブルまたは 1 行のみのテーブル。
UNIQUE
インデックスまたは
PRIMARY KEY
を使う
WHERE
節とともに使用されるテーブルで、インデックス部分のすべてが定数式とともに使用され、そのインデックス部分が
NOT NULL
として定義されている場合。
次のテーブルはすべて定数テーブルとして使用される。
SELECT * FROM t WHEREprimary_key
=1; SELECT * FROM t1,t2 WHERE t1.primary_key
=1 AND t2.primary_key
=t1.id;
テーブルを結合する最適な結合の組み合わせは、すべての可能性を試行してみることで発見される。ORDER
BY
および GROUP
BY
内のすべてのカラムが 1
つのテーブルに存在する場合、結合を行うときは第一にこのテーブルが選ばれる。
ORDER BY
節とそれと異なる GROUP
BY
節がある場合、あるいは、ORDER
BY
または GROUP
BY
に結合キューの第 1
テーブルとは異なるテーブルのカラムが含まれている場合は、一時テーブルが作成される。
SQL_SMALL_RESULT
を使用する場合、MySQL
ではメモリー内の一時テーブルが使用される。
オプティマイザがテーブルスキャンをしたほうが効率的と判断しないかぎり、テーブルインデックスごとにクエリーが行われ、スパンがレコードの 30% 以上である最適インデックスが使用される。しかし、現在では一定の率でインデックスかスキャンを使用するか判断されます。今バージョンのオプティマイザはより複雑で、テーブルサイズ、行数、そして I/O ブロックサイズを基準に推定します。
状況によっては、MySQL でデータファイルの参照もせずにインデックスからレコードを読み取れる場合もある。インデックスから使用されるカラムのすべてが数値型の場合、クエリーの解決にはインデックスツリーのみが使用される。
レコードのそれぞれが出力される前に、HAVING
節と一致しないレコードはスキップされる。
非常に高速なクエリーのサンプルをいくつか紹介します。
SELECT COUNT(*) FROMtbl_name
; SELECT MIN(key_part1
),MAX(key_part1
) FROMtbl_name
; SELECT MAX(key_part2
) FROMtbl_name
WHEREkey_part1
=constant
; SELECT ... FROMtbl_name
ORDER BYkey_part1
,key_part2
,... LIMIT 10; SELECT ... FROMtbl_name
ORDER BYkey_part1
DESC,key_part2
DESC, ... LIMIT 10;
MySQL は次のクエリーで、インデックスツリーのみを使用して解決します (インデックスのあるカラムが数値型であると想定)。
SELECTkey_part1
,key_part2
FROMtbl_name
WHEREkey_part1
=val
; SELECT COUNT(*) FROMtbl_name
WHEREkey_part1
=val1
ANDkey_part2
=val2
; SELECTkey_part2
FROMtbl_name
GROUP BYkey_part1
;
次のクエリーは、ソートのパスを分けることなく、ソートしたレコードを取り出すためにインデックスを使用します。
SELECT ... FROMtbl_name
ORDER BYkey_part1
,key_part2
,... ; SELECT ... FROMtbl_name
ORDER BYkey_part1
DESC,key_part2
DESC, ... ;