MySQL mengimbangi baris tak terbatas


114

Saya ingin membuat kueri yang menampilkan semua hasil dalam tabel, tetapi diimbangi dengan 5 dari awal tabel. Sejauh yang saya tahu, MySQL LIMITmembutuhkan batas dan juga offset. Apakah ada cara untuk melakukan ini?


1
Ini adalah pertanyaan yang benar-benar valid, tetapi saya bertanya-tanya apakah yang lebih baik adalah mengambil semuanya dan mengabaikan beberapa rekaman pertama secara terprogram. Mengingat kengerian dari apa yang tampaknya menjadi jawaban terbaik (batas 5, 18446744073709551615), saya sangat menyukai bekerja di sekitar batasan LIMIT MySQL.
cesoid

3
@cesoid bagaimana jika Anda mau limit 5000, 18446744073709551615. Anda tidak akan mengambil 5000 baris tambahan hanya agar kode Anda terlihat cantik.
elipoultorak

@ user3576887 Saya pikir Anda benar, saya baru saja mempertimbangkan pertanyaan di atas dengan asumsi bahwa 5 adalah satu-satunya persyaratan, daripada beberapa jumlah berbeda yang mungkin jauh lebih besar (dan daripada menyelesaikan masalah orang lain).
cesoid

Saya menyarankan bahwa ini adalah tugas yang langka sehingga keburukan solusinya dapat diterima.
Rick James

Jawaban:


151

Dari Manual MySQL di LIMIT :

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 hingga yang terakhir:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
Mengerikan! Saya datang ke sini berharap MySQL membuat klausa Limit opsional, sebagaimana adanya, tetapi juga dengan offset yang disediakan ... tapi tidak! Saya telah melihat 18446744073709551615 ini tersebar di seluruh kode dan saya menyalahkan programmer yang malas, tetapi ini adalah fitur desain!
Petruza

8
jawaban yang mengerikan, tapi itu resmi dari MySQL Doc. Apa yang bisa saya katakan @ _ @
GusDeCooL

21
18446744073709551615 adalah 2 ^ 64-1 untuk mereka yang bertanya-tanya. Anda mungkin ingin berhati-hati karena Anda tidak akan dapat menyimpan nilai ini dalam integer 32 bit. Anda harus memastikan Anda menyimpan ini sebagai string untuk memastikan kompatibilitas.
AlicanC

13
Mengerikan! mereka perlu tampil lebih elegan dari itu ... Limit -1atau Limit Nullterlihat cukup masuk akal! atau setidaknya Limit harus menerima subquery sepertiselect * from table limit (select count(*) from table)
vulcan raven

19
gunakan php 'PHP_INT_MAX' untuk menghindari efek overflow.
Karl Adler

24

Seperti yang Anda sebutkan, LIMIT diperlukan, jadi Anda perlu menggunakan batas terbesar, yaitu 18446744073709551615 (maksimum BIGINT yang tidak ditandatangani)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
Wah, apakah ini solusi resmi dari tim MySQL?
Antony

12

Seperti disebutkan dalam jawaban lain, MySQL menyarankan untuk menggunakan 18446744073709551615 sebagai jumlah catatan dalam batas tersebut, tetapi pertimbangkan ini: Apa yang akan Anda lakukan jika Anda mendapatkan 18.446.744.073.709.551.615 catatan kembali? Faktanya, apa yang akan Anda lakukan jika Anda mendapatkan 1.000.000.000 rekaman?

Mungkin Anda memang menginginkan lebih dari satu miliar rekaman, tetapi maksud saya adalah ada batasan jumlah yang Anda inginkan , dan jumlahnya kurang dari 18 triliun. Demi stabilitas, pengoptimalan, dan kemungkinan kegunaan, saya sarankan untuk memberi batasan yang berarti pada kueri. Ini juga akan mengurangi kebingungan bagi siapa saja yang belum pernah melihat nomor yang tampak ajaib itu, dan memiliki manfaat tambahan untuk mengkomunikasikan setidaknya berapa banyak catatan yang ingin Anda tangani sekaligus.

Jika Anda benar-benar harus mendapatkan semua 18 triliun catatan dari database Anda, mungkin yang Anda inginkan adalah mengambilnya dengan kelipatan 100 juta dan mengulang 184 miliar kali.


Anda benar, tetapi menyimpan keputusan ini kepada pengembang bukanlah pilihan yang baik
amd

@ amd Bisakah Anda menjelaskannya sedikit lagi? Saya tidak tahu apa yang Anda coba katakan.
cesoid

1
@cesoid Saya pikir dia mengatakan bahwa devs seharusnya tidak menjadi orang yang sewenang-wenang memilih logika bisnis, yang saya setujui, tetapi hanya sampai titik tertentu. Katakanlah Anda mengembalikan daftar pesanan ke pelanggan. Sangat masuk akal untuk tidak pernah mengembalikan lebih dari, katakanlah, satu juta pada satu waktu, tetapi membatasi hingga 100 dapat menyebabkan kebingungan.
Autumn Leonard

@amd Saya tidak mengatakan bahwa pengembang harus mengubah perilaku aplikasi untuk menghindari penggunaan 18446744073709551615. Saya mengatakan bahwa mereka harus mempertimbangkan apakah menggunakan nomor itu masuk akal sebagai bagian dari implementasi klien atau perancang antarmuka apa pun telah diminta, dan itu sangat tidak mungkin menjadi implementasi yang tepat untuk apa pun. Keputusan untuk menggunakan MySQL mungkin sudah dibuat oleh pengembang tanpa menanyakan apakah akan ada lebih dari 18 triliun sesuatu.
cesoid

5

Pendekatan lain akan memilih kolom autoimcrement dan kemudian memfilternya menggunakan HAVING.

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

Tapi saya mungkin akan tetap menggunakan pendekatan batas tinggi.


terima kasih, dan saya bertanya-tanya bagaimana saya bisa memasukkan kueri seperti itu dalam pernyataan PHP! Maksud saya seperti itu$sql = 'SET @a :=0 SELECT .....';
Reham Fahmy

2

Seperti yang disebutkan orang lain, dari manual MySQL. Untuk mencapai itu, Anda dapat menggunakan nilai maksimum dari int besar unsigned, yaitu angka yang mengerikan ini (18446744073709551615). Tetapi untuk membuatnya sedikit tidak berantakan Anda dapat menggunakan operator bitwise "~" tilde.

  LIMIT 95, ~0

itu bekerja sebagai negasi bitwise. Hasil dari "~ 0" adalah 18446744073709551615.


1
Tidak berfungsi di MariaDB 10.3 :( Saya mencoba keduanya LIMIT 5, ~0dan LIMIT ~0 OFFSET 5. Apakah ini fitur MySQL 8.0?
jurchiks

1
Ini bukan masalah di MySQL 5.7 - sintaks tidak valid.
Jonny Nott

0

Baru hari ini saya membaca tentang cara terbaik untuk mendapatkan data dalam jumlah besar (lebih dari satu juta baris) dari tabel mysql. Salah satu caranya adalah, seperti yang disarankan, menggunakan LIMIT x,ywhere xis the offset dan ybaris terakhir yang ingin Anda kembalikan. Namun, seperti yang saya ketahui, ini bukanlah cara yang paling efisien untuk melakukannya. Jika Anda memiliki kolom autoincrement, Anda dapat dengan mudah menggunakan SELECTpernyataan dengan WHEREklausa yang mengatakan dari rekaman mana Anda ingin memulai.

Sebagai contoh, SELECT * FROM table_name WHERE id > x;

Tampaknya mysql mendapatkan semua hasil saat Anda menggunakan LIMITdan kemudian hanya menampilkan catatan yang sesuai di offset: bukan yang terbaik untuk kinerja.

Sumber: Jawaban atas pertanyaan ini Forum MySQL . Perhatikan saja, pertanyaannya adalah sekitar 6 tahun.


13
Ini akan memberikan hasil yang salah jika Anda pernah menghapus catatan. Metode ini sangat berbahaya, karena sering kali berhasil, dan gagal diam-diam jika tidak.
octern

0

Anda dapat menggunakan pernyataan MySQL dengan LIMIT:

START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;

Diuji di MySQL 5.5.44. Dengan demikian, kita dapat menghindari penyisipan nomor 18446744073709551615.

catatan: transaksi memastikan bahwa variabel @ baris sesuai dengan tabel yang dipertimbangkan dalam pelaksanaan pernyataan.


seperti yang dinyatakan @amd: "pilih hitungan (*) pada tabel dengan 7 juta catatan membutuhkan waktu sekitar 17
detik

-1

Saya tahu bahwa ini sudah tua tetapi saya tidak melihat respons serupa jadi ini adalah solusi yang akan saya gunakan.

Pertama, saya akan menjalankan kueri hitungan di atas tabel untuk melihat berapa banyak catatan yang ada. Kueri ini cepat dan biasanya waktu eksekusi dapat diabaikan. Sesuatu seperti:

SELECT COUNT(*) FROM table_name;

Kemudian saya akan membangun kueri saya menggunakan hasil yang saya dapatkan dari hitungan sebagai batas saya (karena itu adalah jumlah baris maksimum yang mungkin dapat dikembalikan tabel). Sesuatu seperti:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

Atau mungkin sesuatu seperti:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Tentu saja, jika perlu, Anda dapat mengurangi nilai_offset yang diinginkan dari count_result untuk mendapatkan nilai akurat dan aktual untuk dimasukkan sebagai batasnya. Meneruskan nilai "18446744073709551610" tidak masuk akal jika saya benar-benar dapat menentukan batas yang tepat untuk diberikan.


2
pilih hitungan (*) pada tabel dengan catatan 7 juta membutuhkan waktu sekitar 17-an
dan

-7
WHERE .... AND id > <YOUROFFSET>

id dapat berupa kolom numerik yang bertambah otomatis atau unik yang Anda miliki ...


7
Ide buruk. Ini akan memberikan offset yang salah jika Anda pernah menghapus baris.
octern
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.