余分なソートを行わずに 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;
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.