Untuk tujuan pagination, saya perlu menjalankan kueri dengan klausa LIMIT
dan OFFSET
. Tapi saya juga perlu menghitung jumlah baris yang akan dikembalikan oleh kueri itu tanpa klausa LIMIT
dan OFFSET
.
Saya ingin berlari:
SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?
Dan:
SELECT COUNT(*) FROM table WHERE /* whatever */
Pada waktu bersamaan. Adakah cara untuk melakukan itu, terutama cara yang memungkinkan Postgres mengoptimalkannya, sehingga lebih cepat daripada menjalankan keduanya secara individual?
Jawaban:
Iya. Dengan fungsi jendela sederhana:
SELECT *, count(*) OVER() AS full_count FROM tbl WHERE /* whatever */ ORDER BY col1 OFFSET ? LIMIT ?
Ketahuilah bahwa biayanya akan jauh lebih tinggi daripada tanpa jumlah total, tetapi biasanya masih lebih murah daripada dua kueri terpisah. Postgres harus benar-benar menghitung semua baris dengan cara apa pun, yang membebankan biaya tergantung pada jumlah total baris yang memenuhi syarat. Rincian:
Namun , seperti yang ditunjukkan Dani , bila
OFFSET
setidaknya sama banyaknya dengan jumlah baris yang dikembalikan dari kueri dasar, tidak ada baris yang dikembalikan. Jadi kami juga tidak mengertifull_count
.Jika itu tidak dapat diterima, solusi yang mungkin untuk selalu mengembalikan hitungan penuh adalah dengan CTE dan
OUTER JOIN
:WITH cte AS ( SELECT * FROM tbl WHERE /* whatever */ ) SELECT * FROM ( TABLE cte ORDER BY col1 LIMIT ? OFFSET ? ) sub RIGHT JOIN (SELECT count(*) FROM cte) c(full_count) ON true;
Anda mendapatkan satu baris nilai NULL dengan
full_count
penambahan jikaOFFSET
terlalu besar. Lain, itu ditambahkan ke setiap baris seperti di kueri pertama.Jika baris dengan semua nilai NULL adalah kemungkinan hasil yang valid, Anda harus memeriksa
offset >= full_count
untuk menghilangkan keraguan asal baris kosong.Ini masih mengeksekusi kueri dasar hanya sekali. Tapi itu menambahkan lebih banyak overhead ke kueri dan hanya membayar jika itu kurang dari mengulangi kueri dasar untuk hitungan.
Jika indeks yang mendukung tata urutan akhir tersedia, mungkin ada baiknya untuk menyertakan
ORDER BY
dalam CTE (secara berlebihan).sumber
MATERIALIZED
secara default, direferensikan dua kali.)edit: jawaban ini valid saat mengambil tabel yang tidak difilter. Saya akan membiarkannya jika itu bisa membantu seseorang tetapi mungkin tidak menjawab pertanyaan awal dengan tepat.
Jawaban Erwin Brandstetter sempurna jika Anda membutuhkan nilai yang akurat. Namun, pada tabel besar Anda seringkali hanya membutuhkan perkiraan yang cukup bagus. Postgres memberi Anda hal itu dan akan jauh lebih cepat karena tidak perlu mengevaluasi setiap baris:
SELECT * FROM ( SELECT * FROM tbl WHERE /* something */ ORDER BY /* something */ OFFSET ? LIMIT ? ) data RIGHT JOIN (SELECT reltuples FROM pg_class WHERE relname = 'tbl') pg_count(total_count) ON true;
Saya sebenarnya tidak yakin apakah ada keuntungan untuk mengeksternalisasi
RIGHT JOIN
atau memilikinya seperti dalam kueri standar. Itu akan membutuhkan beberapa pengujian.SELECT t.*, pgc.reltuples AS total_count FROM tbl as t RIGHT JOIN pg_class pgc ON pgc.relname = 'tbl' WHERE /* something */ ORDER BY /* something */ OFFSET ? LIMIT ?
sumber
WHERE
klausa dalam kueri Anda. Kueri kedua secara logis salah (mengambil satu baris untuk setiap tabel di DB) - dan lebih mahal bila diperbaiki.Praktik buruknya untuk memanggil dua kali kueri yang sama hanya untuk mendapatkan jumlah baris dari hasil returend. Ini akan memakan waktu eksekusi dan akan membuang sumber daya server.
Lebih baik, Anda dapat menggunakan
SQL_CALC_FOUND_ROWS
kueri yang akan memberi tahu MySQL untuk mengambil jumlah total baris bersama dengan hasil kueri batas.Contoh ditetapkan sebagai:
SELECT SQL_CALC_FOUND_ROWS employeeName, phoneNumber FROM employee WHERE employeeName LIKE 'a%' LIMIT 10; SELECT FOUND_ROWS();
Dalam Query di atas, Cukup tambahkan
SQL_CALC_FOUND_ROWS
opsi di sisa query yang diperlukan dan jalankan baris kedua yaituSELECT FOUND_ROWS()
mengembalikan jumlah baris dalam set hasil yang dikembalikan oleh pernyataan itu.sumber
Tidak.
Mungkin ada beberapa keuntungan kecil yang secara teoritis dapat Anda peroleh dari menjalankannya secara individual dengan mesin yang cukup rumit di bawah kapnya. Namun, jika Anda ingin mengetahui berapa banyak baris yang cocok dengan kondisi, Anda harus menghitungnya, bukan hanya subset LIMITed.
sumber