:: DEVELOPER ZONE
余分なソートを行わずに ORDER BY または GROUP BY の要求に応じるために、MySQL はインデックスを使用する場合があります。
全ての使用されていないインデックス部分と他の部分が WHERE 節内で定数であるカラムである場合、ORDER BY がインデックスに完全にマッチしない場合でもこのインデックスを使用できます。
次のクエリではインデックスを使用して ORDER BY / GROUP BY 部分を解決します。
SELECT * FROM t1 ORDER BY key_part1,key_part2,... SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2 SELECT * FROM t1 WHERE key_part1=constant GROUP BY key_part2 SELECT * FROM t1 ORDER BY key_part1 DESC,key_part2 DESC SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC,key_part2 DESC
MySQL で ORDER BY の解決にインデックスを使用できない場合は以下のとおりです(この場合も MySQL は WHERE 節の条件に一致するレコードの検索にインデックスを使用します)。
複数のキーに対して ORDER BY を実行する場合。
SELECT * FROM t1 ORDER BY key1,key2
連続しないキー部分に対して ORDER BY を実行する場合。
SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2
ASC と DESC が混在している場合。
SELECT * FROM t1 ORDER BY key_part1 DESC,key_part2 ASC
レコードの取り出しに使用されるキーが ORDER BY の実行に使用されるキーと異なる場合。
SELECT * FROM t1 WHERE key2=constant ORDER BY key1
ORDER BY で多くのテーブルとカラムを結合していて、それら全てがレコードの取り出しに使用される最初の非 const テーブルではない場合(これは EXPLAIN で出力される最初のテーブルで、かつ、const メソッドを使用していないテーブル)。
ORDER BY と GROUP BY 式が異なる場合。
使用されたテーブルインデックスが、並び順にレコードを格納していないインデックスタイプの場合(HEAP テーブルの HASH インデックスなど)。
MySQL で結果のソートが必要な場合は、以下のアルゴリズムが使用されます。
キーまたはテーブルスキャンに従ってすべてのレコードが読み取られる。
WHERE 節に一致しないレコードはスキップされる。
ソートキーがバッファ(サイズ sort_buffer)に格納される。
バッファが満杯になると、qsort が実行され結果がテンポラリファイルに格納される。ポインタはソートブロックに保存される(すべてのレコードがソートバッファに適合する場合は、テンポラリファイルが作成されない)。
すべてのレコードが読み取られるまで上記項目が反復される。
MERGEBUFF(7)領域まで、別のテンポラリファイルの 1 ブロックにマルチマージが実行される。最初のファイルの全ブロックが 2 つめのファイルに配置されるまで反復される。
残りが MERGEBUFF2(15)ブロック未満になるまで、以下が反復される。
最終マルチマージでは、レコードに対するポインタ(ソートキーの最終部分)のみが結果ファイルに書き込まれる。
次に、sql/records.cc のコードが使用され、結果ファイルのポインタによってソートされた順序で読み取りが行われる。これを最適化するためローポインタの大きなブロックを読み込み、そのソートを行ってからソートされた順序でレコードバッファにレコードを読み取る(read_rnd_buffer_size)。
EXPLAIN SELECT ... ORDER BY を使用すると、MySQL でインデックスを使用してクエリを解決できるかどうかをチェックできます。extra カラムに Using filesort が出力された場合は、MySQL で ORDER BY の解決にインデックスを使用できません。 See 項5.2.1. 「EXPLAIN 構文(SELECT に関する情報の取得)」。
さらに ORDER BY の速度を上げる必要がある場合はまず、ソートフェーズを実行する必要なく MySQL でインデックスを使用できるかどうかを調べます。これが不可能な場合は、以下を実行できます。
sort_buffer_size 変数の値を増やす。
read_rnd_buffer_size 変数の値を増やす。
tmpdir に空き領域が大量にある専用ディスク上のディレクトリを指定する。
MySQL 4.1 以降を使用している場合、tmpdir に対してコロン :(Windows の場合はセミコロン ;)で区切ったパスの一覧を設定することで、複数の物理ディスク間の負荷を分散させることができる。この物理ディスクは、ラウンドロビン方法で使用される。
注意: これらのパスは、同一ディスクの複数のパーティションではなく、異なる物理ディスクである必要がある。
デフォルトでは、クエリで ORDER BY x,y[,...] と指定した場合と同様に MySQL によってすべての GROUP BY x,y[,...] クエリがソートされます。ORDER BY 節を明示的に記述した場合、ソートは発生するものの、MySQL はスピードを損なうことなくそれを最適化します。
クエリに GROUP BY が含まれていて、もし結果のソートのオーバヘッドを回避したいならば、ORDER BY NULL を指定することでソートを抑止できます。
INSERT INTO foo SELECT a,COUNT(*) FROM bar GROUP BY a ORDER BY NULL;
© 1995-2005 MySQL AB. All rights reserved.
