it-swarm.asia

Apa urutan catatan default untuk pernyataan SELECT di MySQL?

Misalkan Anda memiliki tabel dan data berikut:

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

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

Saat menerbitkan select * from t where k = 10 dengan tidak order by klausa, bagaimana cara MySQL mengurutkan catatan secara default?

76
daisy

Reposting jawaban saya untuk pertanyaan serupa tentang SQL Server:

Di dunia SQL, pesanan bukan properti yang melekat dari set data. Dengan demikian, Anda tidak mendapatkan jaminan dari RDBMS Anda bahwa data Anda akan kembali dalam urutan tertentu - atau bahkan dalam urutan yang konsisten - kecuali jika Anda meminta data Anda dengan klausa ORDER BY.

Jadi, untuk menjawab pertanyaanmu:

  • Namun, MySQL memilah catatan yang diinginkan tanpa jaminan konsistensi.
  • Jika Anda ingin mengandalkan pesanan ini untuk apa pun, Anda harus menentukan pesanan yang Anda inginkan menggunakan ORDER BY. Melakukan hal lain berarti menyiapkan diri untuk kejutan yang tidak diinginkan.

Ini adalah properti dari semua SQL, bukan hanya MySQL. Teks yang relevan di SQL-92 spec adalah:

Jika <order by clause> tidak ditentukan, maka urutan baris Q bergantung pada implementasi.

Ada bit teks yang serupa dalam spesifikasi untuk kursor.

87
Nick Chammas

Urutan baris tanpa adanya ORDER BY klausa mungkin:

  • berbeda antara dua mesin penyimpanan;
  • jika Anda menggunakan mesin penyimpanan yang sama, mungkin berbeda antara dua versi dari mesin penyimpanan yang sama; Contoh di sini , gulir ke bawah ke "Urutan Baris".
  • jika versi mesin penyimpanan sama, tetapi versi MySQL berbeda, mungkin berbeda karena perubahan pengoptimal kueri antara versi tersebut;
  • jika semuanya sama, bisa berbeda karena fase bulan dan itu OK.
29

Penyisipan tidak teratur, kacau, pada saat kedatangan. Indeks yang dibuat memang memiliki urutan di mana elemen dimasukkan di lokasi yang tepat di daftar tertaut yang merupakan indeks. Pikirkan daftar triply linked untuk indeks, di mana Anda memiliki tautan bergerak maju dari satu elemen indeks ke yang berikutnya, tautan melihat ke belakang untuk tujuan traversal dan integritas, dan kemudian satu set petunjuk ke catatan aktual dalam tabel yang cocokkan dengan elemen yang diindeks yang dimaksud.

Data aktual, kacau dalam penyimpanan. Indeks yang terkait dengan data, dipesan dalam penyimpanan dan konstruksi. Tarik data yang sebenarnya, dipesan atau tidak, tergantung pada kueri yang terlibat.

11
James Pulley

Ketika datang ke mesin penyimpanan MEMORY , saya berharap urutannya sesuai urutan penyisipan karena indeks default tata letak adalah HASH bukan BTREE dan tidak ada aspek tata letak indeks yang digunakan. Karena Anda mengindeks k, dan k adalah nilai yang sama, semua kunci memasukkan ember hash yang sama . Karena tidak ada alasan untuk mengasumsikan kompleksitas tambahan untuk mengisi hash bucket, urutan penyisipan paling masuk akal.

Saya mengambil tabel sampel dan data yang sama dan menjalankan 30 INSERTs dan saya mendapatkan ini:

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>

Saya memutuskan untuk menguji menambahkan dua nilai berbeda untuk k: 10 dan 11 saya mendapatkan ini:

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>

Sepertinya urutan penyisipan. k = 11 adalah hash kunci pertama kemudian 10. Bagaimana dengan menyisipkan 10 pertama alih-alih 11? Inilah yang saya dapat:

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>

Ini dengan suara bulat !!! ORDER OF INSERTION adalah jawabannya.

Sidenotes tentang penggunaan indeks untuk mesin penyimpanan MEMORY

Pencarian rentang untuk MEMORY akan memiliki kinerja yang mengerikan.

Saat membuat indeks, Anda dapat menentukan USING BTREE klausa bersama dengan definisi indeks. Ini akan meningkatkan hal-hal untuk kueri rentang.

Mencari baris tertentu akan menghasilkan hasil yang sama dalam kinerja dengan HASH atau BTREE.

UPDATE 2011-09-22 11:18 EDT

Saya belajar sesuatu yang menarik hari ini. Saya membaca tautan yang disediakan oleh @ Laurynas Biveinis dari Percona: Tautan Percona mengatakan sesuatu tentang tabel MEMORY untuk MySQL 5.5.15:

Pemesanan Baris

Dengan tidak adanya ORDER BY, catatan dapat dikembalikan dalam urutan yang berbeda dari implementasi MEMORY sebelumnya. Ini bukan bug. Aplikasi apa pun yang mengandalkan pesanan tertentu tanpa klausa ORDER BY dapat memberikan hasil yang tidak terduga. Pesanan khusus tanpa ORDER BY adalah efek samping dari mesin penyimpanan dan penerapan optimizer kueri yang dapat dan akan berubah antara rilis MySQL minor.

Ini adalah tautan yang baik untuk saya lihat hari ini. Jawaban yang saya berikan menunjukkan bahwa tabel yang saya muat diambil agar saya harapkan HARI INI di MySQL 5.5.12. Seperti yang baru saja ditunjukkan oleh Percona dan @ Laurynas Biveinis , tidak ada jaminan dalam rilis kecil lainnya.

Jadi, daripada mencoba membela jawaban saya, saya lebih suka mempromosikan jawaban dari @ Laurynas Biveinis karena ini adalah info terbaru. Kudos dan topi untuk @ Laurynas Biveinis . Saya juga ingin mengucapkan terima kasih @ eevar karena dengan sopan menunjukkan untuk tidak mempromosikan jawaban versi khusus untuk pertanyaan. Mereka berdua mendapatkan upvote saya hari ini.

5
RolandoMySQLDBA