web-dev-qa-db-ja.com

MySQLのORDER BY FIELD()は内部的にどのように機能しますか

_ORDER BY_句の仕組みとFIELD()関数の仕組みを理解しています。私が理解したいのは、両者がどのように連携してソートするかです。行はどのように取得され、ソート順はどのように導出されますか

_+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)
_

上記のクエリは、

_+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 
_

oRDER BY 3、2、1、4と同じようなもの

質問

  • これは内部でどのように機能しますか?
  • MySQLはどのように行を取得し、ソート順を計算しますか?
  • MySQLはidカラムでソートする必要があることをどのようにして知っていますか?
41
itz_nsn

記録のために

_SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);
_

WHERE句でリストを並べる必要がないため、同様に機能するはずです。

それがどのように機能するかについては、

  • FIELD() は、検索する値が存在する場合に、コンマ区切りリストのインデックス位置を返す関数です。

  • _ORDER BY_の値は、 FIELD() が返すものによって評価されます

あらゆる種類の派手な注文を作成できます

たとえば、 IF() 関数を使用すると、

_SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);
_

これにより、最初の4つのIDがリストの上部に表示されます。それ以外の場合は、下部に表示されます。どうして?

_ORDER BY_では、0または1を取得します。

  • 最初の列が0の場合、最初の4つのIDのいずれかを表示します
  • 最初の列が1の場合、後で表示する

最初の列をDESCで反転させましょう

_SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);
_

_ORDER BY_では、0または1を取得します。

  • 最初の列が1の場合、最初の4つのID以外を表示します。
  • 最初の列が0の場合、最初の4つのIDを元の順序で表示します

あなたの実際の質問

これについて内部的に知りたい場合は、本の pages 189 and 192に進んでください

MySQL Internals

本当の深いダイビングのために。

本質的には、_ORDER *order_(_ORDER BY_式ツリー)というC++クラスがあります。 _JOIN::prepare_では、_*order_はsetup_order()という関数で使用されます。なぜJOINクラスの真ん中にあるのですか? すべてのクエリ、単一のテーブルに対するクエリであっても、常にJOINとして処理されます(私の投稿を参照 JOIN条件とWHERE条件の間に実行の違いはありますか? ?

これらすべてのソースコードは_sql/sql_select.cc_です。

明らかに、_ORDER BY_ツリーはFIELD(id,3,2,1,4)の評価を保持します。したがって、数値0、1、2、3、4は、関係する行への参照を保持しながらソートされる値です。

68
RolandoMySQLDBA

多分これは実際のコードから遠すぎるので、あなたが望むものから十分に低いレベルではありません:

MySQLがインデックスを使用してソートされた順序でデータを取得できない場合、選択されたすべての列といくつかの追加データを含む一時テーブル/結果セットを作成します-それらの1つは、各行のORDER BY式値の結果を格納するためのある種の列です-次に、このtmpテーブルを「filesort」ルーティンに送信し、どの列でソートするかを指定します。その後、行はソートされた順序になっているので、行を1つずつ選択して、選択した列を返すことができます。

1
jkavalik