Bagaimana proses MySQL ORDER BY dan LIMIT dalam kueri?

251

Saya memiliki pertanyaan yang terlihat seperti ini:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

Bagaimana cara ORDER BY berfungsi? Apakah akan memesan semua catatan, lalu mendapatkan 20 yang pertama, atau akankah mendapatkan 20 catatan dan memesannya di publish_datelapangan?

Jika yang terakhir, Anda tidak dijamin benar-benar mendapatkan 20 artikel terbaru.

Alex
sumber
6
Perhatikan bahwa jika beberapa publish_dates sama, memesan oleh mereka tidak memberikan hasil yang menentukan, artinya jika Anda menggunakan LIMITuntuk pagination, Anda mungkin mendapatkan item yang sama di halaman yang berbeda!
Konrad Morawski

Jawaban:

244

Ini akan memesan pertama, lalu mendapatkan 20. Database pertama juga akan memproses apa pun dalam WHEREklausa sebelumnya ORDER BY.

James
sumber
1
Jadi waktunya sama?
Yasar Arafath
7
Salah! LIMITistirahat ORDER BY. Dengan LIMITsebuah ORDER BYhasil pengembalian yang salah. LIMITentah bagaimana mengatur ulang hasil yang disetel dikembalikan olehORDER BY
Green
6
@ Hijau, Anda salah. Baca ini untuk penjelasan: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html Ketika kolom ORDER BY diindeks, ini dapat mengembalikan catatan dalam urutan yang berbeda daripada tanpa LIMIT, ketika ada lebih banyak dari 1 catatan dengan nilai yang sama di kolom itu.
yitwail
1
Salah satu solusi cepat untuk masalah tersebut adalah dengan menambahkan satu kolom lagi untuk dipesan dengan lebih disukai memiliki nilai unik sehingga database mendapatkan aturan yang konsisten untuk memesan baris ketika nilai urutan-demi-kolom pertama sama untuk beberapa baris.
rineez
37

Klausa LIMIT dapat digunakan untuk membatasi jumlah baris yang dikembalikan oleh pernyataan SELECT. LIMIT mengambil satu atau dua argumen numerik, yang keduanya harus berupa konstanta integer nonnegatif (kecuali ketika menggunakan pernyataan yang disiapkan).

Dengan dua argumen, argumen pertama menentukan offset dari baris pertama untuk kembali, dan argumen kedua menentukan jumlah maksimum baris untuk kembali. Offset baris awal adalah 0 (bukan 1):

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

Untuk mengambil semua baris dari offset tertentu hingga akhir set hasil, Anda dapat menggunakan sejumlah besar untuk parameter kedua. Pernyataan ini mengambil semua baris dari baris ke-96 ke baris terakhir:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

Dengan satu argumen, nilai menentukan jumlah baris yang akan dikembalikan dari awal set hasil:

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

Dengan kata lain, LIMIT row_count setara dengan LIMIT 0, row_count.

Semua detail tentang: http://dev.mysql.com/doc/refman/5.0/id/select.html

bensiu
sumber
Bukankah itu mengambil baris 5-14?
Adonis K. Kakoulidis
@ Adonis Tidak, tidak. Contohnya adalah langsung dari Dokumentasi MySQL
dcaswell
Nomor 5 adalah baris ke-6. 5 baris (0 hingga 4) diabaikan.
Phil Perry
1
Tetapi menggunakan LIMIT tanpa ORDER BY dapat memberikan hasil yang tidak konsisten! Sayangnya, seluruh set hasil harus dipesan sebelum LIMIT diterapkan atau DBMS bebas untuk secara sewenang-wenang memesan hasil dan kemudian OFFSET dan LIMIT pada set itu. Saya telah membaca bahwa ini mungkin disebabkan oleh DBMS yang memilih Rencana Kueri alternatif berdasarkan OFFSET dan LIMIT sehingga perintah arbitrer.
Barton
4
pertanyaan menanyakan batas & pesanan oleh. Tetapi jawabannya sama sekali tidak terkait dengan pertanyaan ini
Shen liang
9

Seperti yang dikatakan @James, ia akan memesan semua catatan, lalu mendapatkan 20 baris pertama.

Karena itu, Anda dijamin mendapatkan 20 artikel pertama yang diterbitkan, yang lebih baru tidak akan ditampilkan.

Dalam situasi Anda, saya sarankan Anda tambahkan descke order by publish_date, jika Anda ingin artikel terbaru, maka artikel terbaru akan menjadi yang pertama.

Jika Anda perlu menjaga hasil dalam urutan menaik, dan masih hanya ingin 10 artikel terbaru, Anda dapat meminta mysql untuk mengurutkan hasil Anda dua kali.

Kueri ini di bawah ini akan mengurutkan hasil turun dan membatasi hasilnya hingga 10 (yaitu permintaan di dalam kurung). Itu masih akan diurutkan dalam urutan menurun, dan kami tidak puas dengan itu, jadi kami meminta mysql untuk mengurutkannya sekali lagi. Sekarang kami memiliki hasil terbaru di baris terakhir.

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Jika Anda membutuhkan semua kolom, dilakukan dengan cara ini:

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Saya menggunakan teknik ini ketika saya secara manual menulis pertanyaan untuk memeriksa database untuk berbagai hal. Saya belum menggunakannya di lingkungan produksi, tetapi sekarang ketika saya menandainya, penyortiran tambahan tidak memengaruhi kinerja.

emanciperingsivraren
sumber
2
Penyortiran ekstra Anda secara virtual tidak dapat memiliki dampak terukur pada kinerja karena terbatas pada 10 baris / item saja :-). Secara umum mengurutkan tabel dalam-memori (yang diproduksi oleh sub-pilih) sangat cepat dan hampir tidak dapat diukur kecuali Anda memiliki jutaan baris atau DBMS mem-paging hasil yang diset ke disk karena tidak sesuai dengan memori (dalam hal ini tergantung pada DBMS itu juga dapat membatalkan permintaan).
Martin Kersten
7

Jika ada indeks yang sesuai, dalam hal ini di publish_datelapangan, maka MySQL tidak perlu memindai seluruh indeks untuk mendapatkan 20 catatan yang diminta - 20 catatan akan ditemukan di awal indeks. Tetapi jika tidak ada indeks yang sesuai, maka scan penuh dari tabel akan diperlukan.

Ada artikel Blog Kinerja MySQL dari 2009 tentang ini.

martin clayton
sumber
7

Anda bisa menambahkan [asc] atau [desc] di akhir pesanan dengan mendapatkan catatan paling awal atau terbaru

Misalnya, ini akan memberi Anda catatan terbaru terlebih dahulu

ORDER BY stamp DESC

Tambahkan LIMITklausa setelahnyaORDER BY

Paul
sumber
3
Selamat datang di stackoverflow. Saya pikir Anda mungkin salah paham pertanyaannya. Saya percaya mereka bertanya tentang urutan operasi daripada "bagaimana menyortir". (Tapi ini masih bisa diperdebatkan karena pertanyaan sudah dijawab beberapa saat yang lalu;)
Leigh
5

Anda dapat menggunakan kode ini di SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 mana 0 adalah batas awal catatan & 10 jumlah catatan

gaurangkathiriya
sumber
8
Tidak, itu tidak wajib . LIMIT 10adalah singkatan LIMIT 0,10.
Lawrence Dol
2
ya, tidak diperlukan untuk LIMIT 0,10 Tapi Anda Dapat diminta Suka Batas Ini 10,20
gaurangkathiriya
3

LIMIT biasanya diterapkan sebagai operasi terakhir, jadi hasilnya akan disortir terlebih dahulu dan kemudian dibatasi hingga 20. Bahkan, penyortiran akan berhenti segera setelah 20 hasil penyortiran pertama ditemukan.

Egor Pavlikhin
sumber
11
Kalimat kedua Anda bertentangan dengan yang pertama. Penyortiran tidak dapat berhenti ketika 20 hasil pertama ditemukan karena seperti yang Anda katakan penyortiran akan dilakukan sebelum hasilnya akan dikembalikan. MySQL hanya bisa tahu apa 20 hasil pertama setelah penyortiran selesai.
Tom
@ Tom, sebenarnya bisa, jika memesan dengan kolom yang diindeks. Dijelaskan di sini: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail
-3

Juga sintaks LIMIT berbeda menurut database, misalnya:

mysql - BATAS 1, 2

postgres - BATAS 2 OFFSET 1

harish sharma
sumber