MySQLのSELECTステートメントのレコードのデフォルトの順序は何ですか?


66

次のテーブルとデータがあるとします:

create table t (
    k int,
    v int,
    index k(k)
    ) engine=memory;

insert into t (k, v)
values (10, 1),
       (10, 2),
       (10, 3);

select * from t where k = 10なしで発行するorder by場合、MySQLはデフォルトでどのようにレコードをソートしますか?

回答:


75

SQL Serverに関する同様の質問に対する私の回答を再投稿します。

SQLの世界では、順序は一連のデータに固有のプロパティではありません。したがって、ORDER BY句を使用してデータをクエリしない限り、RDBMSからデータが特定の順序で(または一貫した順序で)戻ってくるという保証はありません。

だから、あなたの質問に答えるために:

  • MySQLは、一貫性を保証することなく、レコードを並べ替えます。
  • この順序に依存する場合は、を使用して目的の順序を指定する必要がありますORDER BY。他のことをするということは、好ましくない驚きに備えて準備することです。

これは、MySQLだけでなく、すべてのSQLのプロパティです。SQL-92仕様の関連テキストは次のとおりです。

<order by句>が指定されていない場合、Qの行の順序は実装に依存します。

カーソルの仕様には、同様のテキストがあります。


26

ORDER BY句がない場合の行の順序は次のとおりです。

  • 2つのストレージエンジン間で異なります。
  • 同じストレージエンジンを使用する場合、同じストレージエンジンの2つのバージョン間で異なる場合があります。ここの例では、「行の順序」までスクロールダウンします。
  • ストレージエンジンのバージョンは同じでも、MySQLのバージョンが異なる場合、クエリオプティマイザーがこれらのバージョン間で変更されるため、異なる場合があります。
  • すべてが同じ場合、ムーンフェイズのために異なる可能性がありますが、それは問題ありません。

10

挿入は、到着時に無秩序で混oticとします。作成されるインデックスには、インデックスであるリンクリストの適切な場所に要素が挿入される順序があります。あるインデックス要素から次のインデックス要素への順方向移動リンク、トラバーサルと整合性の目的のための逆方向リンク、そしてテーブル内の実際のレコードへのポインタのセットがある、インデックスの三重リンクリストを考えてください問題のインデックス付き要素に一致します。

ストレージに混oticとした実際のデータ。データに関連付けられたインデックス。ストレージと構築で順序付けされます。順序付きまたは順序なしのデータの実際のプルは、関連するクエリに依存します。


4

それがに来るときMEMORYストレージエンジンは、私は、デフォルトのインデックスのレイアウトがあるので、順序が挿入の順序であることを期待するHASHのではなくBTREE、インデックスのレイアウトのどちら態様は、使用されています。kにインデックスを付けたため、kは同じ値なので、すべてのキーが同じハッシュバケットに入ります。ハッシュバケットの設定に複雑さが加わると考える理由はないため、挿入の順序が最も理にかなっています。

同じサンプルテーブルとデータを使用して30 INSERT秒実行したところ、次のようになりました。

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.00 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

kに2つの異なる値を追加してテストすることにしました:10と11私はこれを得ました:

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t values
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

挿入の順序のように見えます。k = 11が最初にハッシュされたキーは10でしたが、11の代わりに10を最初に挿入するのはどうですか?これは私が得たものです:

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

全会一致です!!! 挿入順序が答えです。

MEMORYストレージエンジンにインデックスを使用する際の注意事項

MEMORYの範囲検索は、恐ろしいパフォーマンスを発揮します。

インデックスを作成するときに、インデックスUSING BTREEの定義とともに句を指定できます。これにより、範囲クエリの処理が改善されます。

特定の行を検索すると、HASHまたはでパフォーマンスが同じ結果になりますBTREE

更新2011-09-22 11:18 EDT

今日は面白いことを学びました。Perconaの@Laurynas Biveinisが提供するリンクを読みます。Perconaのリンクには、MySQL 5.5.15の MEMORYテーブルに関する情報が記載されています

行の順序付け

ORDER BYがない場合、レコードは以前のMEMORY実装とは異なる順序で返される場合があります。これはバグではありません。ORDER BY句のない特定の順序に依存するアプリケーションは、予期しない結果をもたらす可能性があります。ORDER BYを使用しない特定の順序は、ストレージエンジンとクエリオプティマイザーの実装の副作用であり、MySQLのマイナーリリース間で変更される可能性があります。

これは今日の私にとって良いリンクでした。私が与えた答えは、ロードしたテーブルが、MySQL 5.5.12で今日の予定どおりに取得されたことを示しています。Perconaと@Laurynas Biveinisが指摘したように、別のマイナーリリースでは保証はありません。

それで、私の答えを弁護しようとするのではなく、@ Laurynas Biveinisからの答えを宣伝したいのです。なぜならそれは最新の情報だからです。以下のための賞賛と帽子オフ@Laurynas Biveinis。また、質問に対するバージョン固有の回答を宣伝しないよう丁寧に指摘してくれた@eevarにも感謝します。彼らは両方とも私の今日の賛成を得ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.