:: DEVELOPER ZONE
WHERE の最適化は、ほとんどの場合 SELECT とともに使用されるため、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 回に限られる。
WHERE がない単一テーブルの COUNT(*) は、MyISAM と HEAP テーブルのテーブル情報から直接取り出される。
これは、テーブル 1 つのみで使用する場合はすべての NOT NULL 式でも実行される。
無効定数式の早期検出。MySQL は実行不可能な SELECT ステートメントがある場合、それを迅速に検出し、結果としてレコードを返さない。
GROUP BY またはグループ関数(COUNT()、MIN()。..)を使用しない場合、HAVING は WHERE とマージされる。
サブ結合のそれぞれに、単純な WHERE が構造化され、サブ結合ごとに迅速に WHERE 評価を取得し、可能な限り迅速にレコードをスキップする。
クエリ内の他のすべてのテーブルの前に、まず、すべての定数テーブルが読み込まれる。 定数テーブルとは以下のものを指す。
空白テーブルまたは 1 レコードのみのテーブル。
UNIQUE インデックスまたは PRIMARY KEY を使う WHERE 節とともに使用されるテーブルで、インデックス部分のすべてが定数式とともに使用され、そのインデックス部分が NOT NULL として定義されている場合。
以下のテーブルはすべて定数テーブルとして使用される。
mysql> SELECT * FROM t WHERE primary_key=1;
mysql> 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% 未満である最適インデックスが使用される。このようなインデックスが検索されない場合は、クイックテーブルスキャンが使用される。
状況によっては、MySQL でデータファイルの参照もせずにインデックスからレコードを読み取れる場合もある。インデックスから使用されるカラムのすべてが数値型の場合、クエリの解決にはインデックスツリーのみが使用される。
レコードのそれぞれが出力される前に、HAVING 節と一致しないレコードはスキップされる。
非常に高速なクエリのサンプルをいくつか紹介します。
mysql> SELECT COUNT(*) FROM tbl_name;
mysql> SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
mysql> SELECT MAX(key_part2) FROM tbl_name
-> WHERE key_part_1=constant;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1,key_part2,... LIMIT 10;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;
次のクエリは、インデックスツリーのみを使用して解決されます(インデックスのあるカラムが数値型であると想定)。
mysql> SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
mysql> SELECT COUNT(*) FROM tbl_name
-> WHERE key_part1=val1 AND key_part2=val2;
mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;
The following queries use indexing to retrieve the rows in sorted order without a separate sorting pass: 次のクエリは、ソートのパスを分けることなく、ソートしたレコードを取り出すためにインデックスを使用します。
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1,key_part2,... ;
mysql> SELECT ... FROM tbl_name
-> ORDER BY key_part1 DESC,key_part2 DESC,... ;
© 1995-2005 MySQL AB. All rights reserved.
