Bagaimana cara ORDER BY FIELD () di MySQL bekerja secara internal

37

Saya mengerti bagaimana ORDER BYklausa bekerja dan bagaimana FIELD()fungsinya bekerja. Yang ingin saya pahami adalah bagaimana keduanya bekerja sama untuk menyortir. Bagaimana baris diambil dan bagaimana urutan sortir diturunkan

+----+---------+
| 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)

Kueri di atas akan menghasilkan

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

sesuatu yang mirip dengan mengatakan ORDER OLEH 3, 2, 1, 4

PERTANYAAN

  • Bagaimana cara kerjanya secara internal?
  • Bagaimana cara MySQL mendapatkan baris, dan menghitung urutan pengurutan?
  • Bagaimana MySQL tahu harus mengurutkan berdasarkan kolom id?
itz_nsn
sumber
1
coba variasi kueri Anda ini: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);Kemudian tambahkan ORDER BY fatau ORDER BY FIELD(id,3,2,1,4)dan coba lagi.
ypercubeᵀᴹ

Jawaban:

64

Untuk catatan

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

harus bekerja juga karena Anda tidak perlu memesan daftar di WHEREklausa

Adapun cara kerjanya,

  • FIELD () adalah fungsi yang mengembalikan posisi indeks daftar yang dibatasi koma jika nilai yang Anda cari ada.

  • The ORDER BYnilai dievaluasi oleh apa yang LAPANGAN () return

Anda dapat membuat segala macam pesanan mewah

Misalnya, menggunakan IF () function

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);

Ini akan menyebabkan 4 id pertama muncul di bagian atas daftar, Jika tidak, ia muncul di bagian bawah. Mengapa?

Di ORDER BY, Anda mendapatkan 0 atau 1.

  • Jika kolom pertama adalah 0, buat salah satu dari 4 id pertama yang muncul
  • Jika kolom pertama adalah 1, buatlah itu muncul sesudahnya

Mari kita balikkan dengan DESC di kolom pertama

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);

Di ORDER BY, Anda masih mendapatkan 0 atau 1.

  • Jika kolom pertama adalah 1, buat apa saja selain 4 id pertama yang muncul.
  • Jika kolom pertama adalah 0, buat 4 id pertama muncul dalam urutan asli

PERTANYAAN SEBENARNYA

Jika Anda benar-benar ingin masalah internal ini, baca halaman 189 dan 192 dari Buku

MySQL Internal

untuk menyelam yang sangat dalam.

Intinya, ada kelas C ++ yang disebut ORDER *order( ORDER BYPohon ekspresi). In JOIN::prepare, *orderdigunakan dalam fungsi yang disebut setup_order(). Kenapa di tengah JOINkelas? Setiap kueri, bahkan kueri terhadap satu tabel selalu diproses sebagai GABUNG (Lihat posting saya Apakah ada perbedaan eksekusi antara kondisi GABUNG dan kondisi DIMANA? )

Kode sumber untuk semua ini adalah sql/sql_select.cc

Jelas, ORDER BYpohon itu akan mengadakan evaluasi FIELD(id,3,2,1,4). Dengan demikian, angka 0,1,2,3,4 adalah nilai yang sedang disortir sambil membawa referensi ke baris yang terlibat.

RolandoMySQLDBA
sumber
1
Ini adalah penjelasan yang sangat bagus. Dengan menggunakan metode ini saya bisa mendapatkan 3 pesanan, nilai pertama primer yang merupakan maks dari set, kemudian oleh FIELD, lalu oleh kolom lain untuk yang tidak dalam set FIELD. Sesuatu yang tidak saya impikan beberapa waktu lalu. Terima kasih telah meluangkan waktu untuk benar-benar menjelaskan cara kerjanya.
Lizardx
Misalkan ada Nnilai di keduanya INdan FIELD. Dalam contoh ini N=4. Apakah saya mengerti benar bahwa permintaan ini akan melakukan setidaknya ~N^2operasi. Karena setiap FIELDperhitungan membuat ~Nperbandingan satu kali untuk setiap baris. Jika demikian, ini cukup lambat untuk besar. NMungkin itu bukan pendekatan yang sangat baik?
Gherman
@ Gherman FIELD()Fungsi ini harus O(1)operasi karena FIELD()memiliki indeks numerik id. Jadi saya tidak melihat yang lain kecuali O(n)berdasarkan baris. Saya tidak melihat FIELD()melakukan operasi berulang seperti yang GREATEST()perlu dilakukan.
RolandoMySQLDBA
@RolandoMySQLDBA Maksud saya adalah jika FIELDmemiliki Nargumen untuk dibandingkan maka akan menjalankan Nperbandingan. Bagaimana lagi jika membandingkan satu angka dengan Nangka lainnya jika tidak dengan melakukan O(N)? Satu-satunya kemungkinan yang dapat saya pikirkan adalah beberapa jenis optimasi melalui struktur data khusus seperti hash atau pohon argumen. Sebenarnya saya tahu bahwa INmemang memiliki optimasi seperti itu. Saya tidak tahu FIELD. Apa yang Anda maksud dengan "indeks numerik"?
Gherman
1
Hai @RaymondNijland, Pernyataan CASE lebih mudah dimengerti. Untuk kasus ini, gula sintaksis hanya memiliki sedikit tulisan.
RolandoMySQLDBA
1

Mungkin ini akan terlalu jauh dari kode sebenarnya sehingga tidak cukup rendah dari yang Anda inginkan:

Ketika MySQL tidak dapat menggunakan indeks untuk mengambil data dalam urutan terurut, ia membuat tabel / resultset sementara dengan semua kolom yang dipilih dan beberapa data tambahan - salah satunya adalah semacam kolom untuk menyimpan hasil ORDER BY nilai ekspresi untuk setiap baris - kemudian mengirimkan tabel tmp ini ke rutine "filesort" dengan info kolom mana yang akan diurut. Setelah itu, baris-baris tersebut disusun dalam urutan sehingga dapat memilih satu per satu dan mengembalikan kolom yang dipilih.

jkavalik
sumber
Penjelasan ini tidak memperhitungkan bagaimana FIELDfungsi dalam dihitung. Saya khawatir itu mungkin berdampak signifikan pada kinerja.
Gherman
@ Gherman Saya tidak berpikir begitu, kecuali jika Anda menggunakan daftar argumen yang sangat panjang (karena fungsinya linier ke sejumlah argumen . Akses data adalah urutan besarnya lebih lambat daripada perbandingan sederhana
jkavalik
Ya, daftar panjang argumen. Ada banyak argumen seperti halnya catatan dalam contoh ini.
Gherman
Saya hanya akan memberi label ratusan atau ribuan, dan kemudian Anda mendapatkan masalah lain (ukuran permintaan, dll.)
jkavalik
mengapa tidak ratusan hasil? Apakah ini banyak?
Gherman