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


37

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カラムでソートする必要があることをどのように知っていますか?

1
クエリのこのバリエーションを試してください:SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);その後、ORDER BY fまたはORDER BY FIELD(id,3,2,1,4)を追加してから再試行してください。
ypercubeᵀᴹ

回答:


64

記録のために

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

WHERE句のリストを順序付ける必要がないため、同様に機能するはずです

仕組みについては、

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

たとえば、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を元の順序で表示します

あなたの実際の質問

これについて真剣に知りたい場合は、本の189ページと192ページに進んでください

MySQL内部

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

本質的に、ORDER *orderORDER 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は、関連する行への参照を保持しながらソートされる値です。


1
これは非常に優れた説明です。これらの方法を使用して、3つの注文を取得することができました。最初の値はセットの最大値であり、FIELD、FIELDセットにない列の別の列です。しばらく前には夢にも思わなかったもの。これが実際にどのように機能するかを本当に説明してくれてありがとう。
リザード

あると仮定しN、両方の値INとはFIELD。この例ではN=4。このクエリが少なくとも~N^2操作を実行することを正しく理解していますか。各FIELD計算は~N行ごとに1回比較を行うためです。もしそうなら、これは大きなために非常に遅いNかもしれません多分それは非常に良いアプローチではありませんか?
ガーマン

@Gherman FIELD()関数は数値インデックスがあるO(1)ため、操作である必要がありFIELD()ますid。そのためO(n)、行に基づいてしか表示されません。必要FIELD()な反復操作を実行しているようには見えGREATEST()ません。
RolandoMySQLDBA

@RolandoMySQLDBA私のポイントがあればということであるFIELD持っているNと比較するための引数を、それが実行されるN比較を。それ以外のN場合、1つの数値を他の数値と比較することはありO(N)ますか?私が考えることができる唯一の可能性は、ハッシュや引数のツリーのような特別なデータ構造によるある種の最適化です。実際、そのINような最適化があることは知っています。私は知らないFIELD。「数値インデックス」とはどういう意味ですか?
ガーマン

1
@RaymondNijlandさん、CASEステートメントの方がわかりやすいです。
RolandoMySQLDBA

1

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

MySQLはインデックスを使用してソートされた順序でデータを取得できない場合、選択されたすべての列といくつかの追加データを含む一時テーブル/結果セットを作成します。次に、このtmpテーブルを「filesort」ルーチンに送信し、どの列でソートするかという情報を送信します。その後、行はソートされた順序になり、1行ずつ選択して選択した列を返すことができます。


この説明では、FIELD関数の計算方法を考慮していません。パフォーマンスに重大な影響を及ぼす可能性があると思います。
ガーマン

@Gherman非常に長い引数リストを使用していない限り、そうは思いません(関数は引数の数に対して線形です。データアクセスは単純な比較よりも桁違いに遅いです。)
jkavalik

はい、引数の長いリスト。この例には、レコードと同じ数の引数があります。
ガーマン

数百または数千のラベルを付けるだけで、とにかく他の問題(クエリサイズなど)が発生します
jkavalik

何百もの結果が得られないのはなぜですか?たくさんありますか?
ガーマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.