Home / Artikel / Web Development
Web Development

Pagination Offset vs Cursor: Cara Menampilkan Data Banyak Tanpa Membuat Website Lambat

Pagination bukan sekadar membagi daftar menjadi beberapa halaman. Cara memilih offset atau cursor dapat memengaruhi kecepatan query, kestabilan hasil, dan pengalaman pengguna ketika data terus berubah.

Pagination Offset vs Cursor: Cara Menampilkan Data Banyak Tanpa Membuat Website Lambat

Ketika sebuah website mulai memiliki ribuan atau jutaan data, menampilkan semuanya dalam satu halaman bukan lagi pilihan yang masuk akal. Selain membuat waktu muat menjadi panjang, cara ini juga membebani database dan browser pengguna.

Di titik inilah pagination dibutuhkan. Pagination adalah teknik membagi data menjadi beberapa bagian, misalnya 20 atau 50 item per permintaan. Namun, memilih cara pagination yang keliru dapat menimbulkan masalah baru: halaman berikutnya terasa lambat, data bergeser saat pengguna sedang membaca, atau hasil API menjadi tidak konsisten.

Dua pendekatan yang paling sering digunakan adalah offset pagination dan cursor pagination. Keduanya bisa benar, tetapi cocok untuk situasi yang berbeda.

Offset pagination: sederhana dan mudah dipahami

Offset pagination bekerja dengan konsep “lewati sejumlah data, lalu ambil beberapa item berikutnya”. Misalnya, halaman pertama mengambil data mulai dari posisi 0, halaman kedua melewati 20 data, dan seterusnya.

Contoh query MySQL-nya seperti ini:

SELECT id, title, created_at
FROM articles
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;

Query tersebut mengambil 20 artikel setelah melewati 40 artikel pertama. Dalam aplikasi, nilai OFFSET biasanya dihitung dari nomor halaman:

$offset = ($page - 1) * $perPage;

Kelebihan utamanya adalah mudah diterapkan. URL seperti /articles?page=3 mudah dipahami pengguna, mudah diuji, dan cocok untuk halaman yang membutuhkan navigasi langsung ke halaman tertentu.

Offset juga nyaman untuk tabel admin. Pengguna biasanya ingin melompat ke halaman 10, melihat jumlah halaman, atau mengurutkan data berdasarkan kolom tertentu. Untuk kebutuhan seperti ini, pendekatan offset sering kali sudah cukup.

Masalah offset ketika data semakin besar

Offset terlihat sederhana, tetapi database tetap harus menemukan dan melewati baris-baris sebelum mengambil hasil yang diminta. Pada offset kecil, perbedaannya mungkin tidak terasa. Namun, pada halaman yang sangat jauh, proses ini dapat menjadi lebih berat.

Misalnya, permintaan untuk mengambil data dengan OFFSET 500000 berarti database perlu menelusuri banyak baris sebelum memberikan 20 hasil terakhir. Index dapat membantu, tetapi tidak selalu menghilangkan biaya tersebut.

Masalah lain muncul ketika data berubah di antara dua permintaan. Bayangkan pengguna sedang melihat halaman pertama daftar komentar. Sebelum ia membuka halaman kedua, ada komentar baru yang masuk di bagian paling atas. Karena posisi data bergeser, beberapa komentar dapat muncul dua kali atau justru terlewat.

Ini bukan bug yang selalu mudah terlihat. Pada data yang jarang berubah, semuanya mungkin tampak baik-baik saja. Namun, pada feed berita, aktivitas pengguna, log, atau transaksi yang terus bertambah, efeknya bisa mengganggu.

Cursor pagination: melanjutkan dari item terakhir

Cursor pagination tidak mengandalkan nomor halaman. Sistem menyimpan penanda dari item terakhir yang sudah diterima, lalu menggunakan penanda tersebut untuk mencari data berikutnya.

Contoh sederhananya, aplikasi mengambil artikel terbaru berdasarkan created_at dan id. Setelah menerima 20 artikel, aplikasi mencatat artikel terakhir sebagai cursor. Permintaan berikutnya meminta data yang lebih lama dari titik tersebut.

SELECT id, title, created_at
FROM articles
WHERE (created_at, id) < ('2026-09-19 10:30:00', 8421)
ORDER BY created_at DESC, id DESC
LIMIT 20;

Dalam contoh ini, pasangan created_at dan id dipakai sebagai penentu posisi. Pemakaian dua kolom penting karena waktu pembuatan bisa sama untuk beberapa baris. id menjadi pembeda agar urutannya tetap jelas.

Cursor biasanya dikirim dalam URL atau respons API, misalnya:

{
"data": [...],
"next_cursor": "eyJpZCI6ODQyMX0="
}

Cursor tersebut sering kali dibuat dalam bentuk token yang telah disandikan. Tujuannya bukan untuk menyembunyikan data secara mutlak, melainkan agar detail internal query tidak perlu ditampilkan langsung kepada pengguna.

Kapan cursor lebih cocok?

Cursor pagination cocok untuk data yang jumlahnya besar dan terus berubah. Contohnya adalah timeline, daftar notifikasi, riwayat aktivitas, pesan, katalog produk besar, dan endpoint API yang dikonsumsi aplikasi mobile.

Karena query dimulai dari posisi tertentu dan memanfaatkan index, cursor biasanya lebih stabil untuk mengambil data secara berurutan. Sistem tidak perlu melewati ratusan ribu baris hanya untuk mendapatkan halaman yang jauh.

Namun, cursor memiliki keterbatasan. Pengguna tidak dapat dengan mudah melompat langsung ke halaman 50. Konsepnya lebih dekat dengan tombol “Muat lebih banyak” atau infinite scroll daripada navigasi halaman klasik.

Pastikan urutan data benar-benar stabil

Baik offset maupun cursor membutuhkan urutan data yang konsisten. Hindari melakukan pagination tanpa ORDER BY yang jelas. Tanpa urutan, database tidak berkewajiban mengembalikan baris dalam susunan yang sama pada setiap permintaan.

Jika memakai satu kolom yang nilainya bisa sama, tambahkan kolom pembeda. Contohnya:

ORDER BY created_at DESC, id DESC

Urutan gabungan seperti ini membuat posisi setiap item lebih deterministik. Pastikan pula kolom yang digunakan untuk filter dan pengurutan memiliki index yang sesuai. Untuk query cursor di atas, index gabungan pada created_at dan id dapat membantu database mencari data dengan lebih efisien.

Jangan lupa total data dan penghitungan count

Pada offset pagination, halaman biasanya membutuhkan informasi seperti total data dan jumlah halaman. Informasi ini sering diperoleh melalui query COUNT(*). Untuk tabel besar, penghitungan total secara terus-menerus dapat menjadi beban tambahan.

Cursor pagination biasanya tidak perlu mengetahui jumlah total halaman. Respons cukup memberi tahu apakah masih ada data berikutnya melalui next_cursor atau nilai seperti has_more.

Ini membawa konsekuensi pada desain antarmuka. Jika produk membutuhkan tulisan “Menampilkan halaman 3 dari 120”, offset lebih natural. Jika tujuan utamanya adalah membaca data terbaru secara berurutan, cursor sering kali lebih sederhana dan efisien.

Apa artinya bagi kita?

Pagination sebaiknya dipilih berdasarkan cara pengguna berinteraksi dengan data, bukan hanya berdasarkan kebiasaan developer.

  • Gunakan offset untuk tabel admin, laporan, atau daftar yang membutuhkan nomor halaman.
  • Gunakan cursor untuk feed, log, notifikasi, dan data besar yang terus berubah.
  • Gunakan urutan yang stabil dengan kombinasi kolom utama dan kolom pembeda.
  • Pastikan kolom filter serta pengurutan didukung index yang sesuai.
  • Batasi nilai limit dari sisi server agar klien tidak meminta ribuan data sekaligus.
  • Uji pagination dengan data yang benar-benar banyak, bukan hanya 50 baris di lingkungan lokal.

Yang bisa dilakukan sekarang

Mulailah dengan memeriksa endpoint atau halaman yang menampilkan daftar data. Catat query yang dijalankan, ukuran tabel, waktu respons, dan perilaku ketika data baru masuk di tengah proses membaca.

Jika daftar tersebut membutuhkan navigasi halaman dan jumlah total data, offset kemungkinan merupakan pilihan praktis. Jika pengguna hanya perlu memuat data berikutnya secara berurutan, pertimbangkan cursor. Apa pun pilihannya, ukur dengan data realistis dan perhatikan pengalaman pengguna, bukan hanya waktu query di satu kondisi.

Pagination yang baik tidak terlihat oleh pengguna. Daftar terasa lancar, hasil tidak tiba-tiba meloncat, dan database tidak bekerja lebih keras dari yang diperlukan.

– Rio Yotto @rioyotto