Saya bertanya-tanya apakah ada cara untuk mendapatkan jumlah hasil dari kueri MySQL, dan pada saat yang sama membatasi hasilnya.
Cara kerja pagination (seperti yang saya pahami), pertama-tama saya melakukan sesuatu seperti
query = SELECT COUNT(*) FROM `table` WHERE `some_condition`
Setelah saya mendapatkan num_rows (query), saya mendapatkan jumlah hasil. Tetapi kemudian untuk benar-benar membatasi hasil saya, saya harus melakukan kueri kedua seperti:
query2 = SELECT COUNT(*) FROM `table` WHERE `some_condition` LIMIT 0, 10
Pertanyaan saya: Apakah ada cara untuk mengambil jumlah total hasil yang akan diberikan, DAN membatasi hasil yang dikembalikan dalam satu kueri? Atau cara yang lebih efisien untuk melakukan ini. Terima kasih!
mysql
pagination
double
atp
sumber
sumber
Jawaban:
Tidak, berapa banyak aplikasi yang ingin melakukan paginasi harus melakukannya. Ini dapat diandalkan dan anti peluru, meskipun itu membuat kueri dua kali. Tetapi Anda dapat menyimpan hitungan ke cache selama beberapa detik dan itu akan banyak membantu.
Cara lain adalah dengan menggunakan
SQL_CALC_FOUND_ROWS
klausa dan kemudian memanggilSELECT FOUND_ROWS()
. Terlepas dari kenyataan bahwa Anda harus melakukanFOUND_ROWS()
panggilan setelahnya, ada masalah dengan ini: Ada bug di MySQL yang menggelitik ini yang memengaruhiORDER BY
kueri sehingga membuatnya jauh lebih lambat di tabel besar daripada pendekatan naif dari dua kueri.sumber
Saya hampir tidak pernah melakukan dua pertanyaan.
Cukup kembalikan satu baris lagi dari yang dibutuhkan, hanya tampilkan 10 pada halaman, dan jika ada lebih dari yang ditampilkan, tampilkan tombol "Next".
Kueri Anda harus kembali dalam urutan yang paling relevan terlebih dahulu. Kemungkinannya adalah, kebanyakan orang tidak akan peduli untuk membuka halaman 236 dari 412.
Saat Anda melakukan pencarian Google, dan hasil Anda tidak ada di halaman pertama, Anda kemungkinan besar akan pergi ke halaman dua, bukan sembilan.
sumber
COUNT
adalah fungsi agregat. Bagaimana Anda mengembalikan hitungan dan semua hasil dalam satu kueri? Kueri di atas hanya akan mengembalikan 1 baris, apa pun yangLIMIT
disetel. Jika Anda menambahkanGROUP BY
, itu akan mengembalikan semua hasil tetapiCOUNT
akan tidak akuratPendekatan lain untuk menghindari pembuatan kueri ganda adalah dengan mengambil semua baris untuk halaman saat ini menggunakan klausa LIMIT terlebih dahulu, kemudian hanya melakukan kueri COUNT (*) kedua jika jumlah baris maksimum telah diambil.
Dalam banyak aplikasi, hasil yang paling mungkin adalah semua hasil muat di satu halaman, dan harus melakukan penomoran halaman adalah pengecualian daripada norma. Dalam kasus ini, kueri pertama tidak akan mengambil jumlah hasil maksimum.
Misalnya, jawaban atas pertanyaan stackoverflow jarang muncul di halaman kedua. Komentar pada jawaban jarang melebihi batas 5 atau lebih yang diperlukan untuk menampilkan semuanya.
Jadi dalam aplikasi ini Anda cukup melakukan kueri dengan LIMIT terlebih dahulu, dan kemudian selama batas itu tidak tercapai, Anda tahu persis berapa banyak baris yang ada tanpa perlu melakukan kueri COUNT (*) kedua - yang seharusnya mencakup sebagian besar situasi.
sumber
Dalam kebanyakan situasi, jauh lebih cepat dan lebih sedikit sumber daya untuk melakukannya dalam dua kueri terpisah daripada melakukannya dalam satu kueri, meskipun hal itu tampaknya kontra-intuitif.
Jika Anda menggunakan SQL_CALC_FOUND_ROWS, maka untuk tabel besar itu membuat kueri Anda jauh lebih lambat, jauh lebih lambat bahkan daripada menjalankan dua kueri, yang pertama dengan COUNT (*) dan yang kedua dengan LIMIT. Alasannya adalah karena SQL_CALC_FOUND_ROWS menyebabkan klausa LIMIT diterapkan setelah mengambil baris, bukan sebelumnya, sehingga mengambil seluruh baris untuk semua kemungkinan hasil sebelum menerapkan batas. Ini tidak dapat dipenuhi oleh indeks karena itu benar-benar mengambil data.
Jika Anda mengambil pendekatan dua kueri, yang pertama hanya mengambil JUMLAH (*) dan tidak benar-benar mengambil dan data aktual, ini dapat dipenuhi jauh lebih cepat karena biasanya dapat menggunakan indeks dan tidak harus mengambil data baris sebenarnya untuk setiap baris yang dilihatnya. Lalu, kueri kedua hanya perlu melihat baris $ offset + $ limit pertama lalu kembali.
Posting dari blog kinerja MySQL ini menjelaskan lebih lanjut:
http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
Untuk informasi lebih lanjut tentang mengoptimalkan pagination, periksa posting ini dan posting ini .
sumber
Jawaban saya mungkin terlambat, tetapi Anda dapat melewati kueri kedua (dengan batasnya) dan hanya memfilter info melalui skrip back end Anda. Dalam PHP misalnya, Anda dapat melakukan sesuatu seperti:
Tetapi tentu saja, ketika Anda memiliki ribuan catatan untuk dipertimbangkan, itu menjadi tidak efisien dengan sangat cepat. Hitungan yang sudah dihitung sebelumnya mungkin ide yang bagus untuk dilihat.
Berikut bacaan yang bagus tentang subjek: http://www.percona.com/ppc2009/PPC2009_mysql_pagination.pdf
sumber
sumber
where
klausa ke kueri bagian dalam dan Anda mendapatkan "total" yang benar bersama dengan hasil halaman (halaman dipilih denganlimit
klausaUntuk siapapun yang mencari jawaban di tahun 2020. Sesuai dokumentasi MySQL:
"Pengubah kueri SQL_CALC_FOUND_ROWS dan fungsi FOUND_ROWS () yang menyertai tidak digunakan lagi mulai MySQL 8.0.17 dan akan dihapus di versi MySQL yang akan datang. Sebagai gantinya, pertimbangkan untuk mengeksekusi kueri Anda dengan LIMIT, lalu kueri kedua dengan COUNT (*) dan tanpa LIMIT untuk menentukan apakah ada baris tambahan. "
Saya rasa itu sudah cukup.
https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_found-rows
sumber
Anda dapat menggunakan kembali sebagian besar kueri dalam subkueri dan menyetelnya ke pengenal. Misalnya, permintaan film yang menemukan film yang berisi urutan surat berdasarkan runtime akan terlihat seperti ini di situs saya.
Perhatikan bahwa saya bukan ahli database, dan saya berharap seseorang dapat mengoptimalkannya sedikit lebih baik. Karena berdiri menjalankannya langsung dari antarmuka baris perintah SQL, mereka berdua membutuhkan ~ 0,02 detik di laptop saya.
sumber
sumber