Teknik Mengaplikasikan Pagination: OFFSET vs SEEK Pagination

Teknik Mengaplikasikan Pagination: OFFSET vs SEEK Pagination

Mon, Aug 20, 2018 7:33 PM
Engineering by Hafiz Hanindito

Pagination adalah suatu metode untuk membagi suatu dokumen/resource menjadi bagian-bagian lebih kecil yang saling terpisah. Dalam dunia web development, istilah pagination umumnya merujuk pada teknik untuk membagi resource yang besar (data suatu tabel di database misalnya) menjadi komponen lebih kecil yang lebih mudah ditangani oleh user (manusia). Contoh yang umum dari penggunaan pagination ini adalah ketika kita melakukan suatu query melalui google. Hasil dari query google sering mengandung hasil hingga jutaan items; jumlah yang terlalu besar untuk dapat langsung diperoleh oleh kebanyakan user. Oleh karenanya hasil tersebut dibagi oleh google ke dalam beberapa halaman yang tiap-tiapnya mengandung 10 items (konfigurasi default).

Contoh implementasi pagination metode OFFSET adalah sebagai berikut:

SELECT *
  FROM sales
 ORDER BY sale_date DESC
 LIMIT 10 OFFSET 10

Sederhananya, query di atas meminta database untuk mengembalikan data dari tabel sales sebanyak 10, dimulai dari row ke-11 (setelah men-skip 10 baris data pertama). Dalam implementasi ini, jika kita ingin mengakses data di halaman lain, satu-satunya bagian yang perlu kita ubah dari query ini adalah nilai OFFSETnya.

Di sisi lain, jika kita menggunakan metode SEEK, maka contoh implementasinya adalah sebagai berikut:

SELECT *
  FROM sales
 WHERE sale_date < ?
 ORDER BY sale_date DESC
 LIMIT 10

Dalam implementasi metode SEEK ini, maka nilai yang berubah-ubah untuk dapat men-generate data untuk ditampilkan halaman-halaman selanjutnya adalah bagian (?). Nilai ini, yang bisa kita sebut sebagai kursor karena fungsinya sebagai penunjuk, menjadi basis seleksi data yang harus di-track oleh aplikasi kita.

Bagi kalian yang cukup jeli, maka tentunya menyadari kesamaan yang penting dari kedua implementasi tersebut, yaitu kebergantungan kepada nilai sort order yang tetap (dalam kasus ini, dari nilai sale_date). Dalam kasus OFFSET, query akan menyortir data, kemudian melakukan count dari data pertama hingga ke OFFSET, untuk kemudian mengambil n data sebanyak yang ditentukan oleh LIMIT. Oleh karenanya, nilai sale_date tidak perlu bersifat unik dan pagination berbasis OFFSET tetap berjalan dengan baik.

Sedangkan untuk kasus implementasi berdasarkan metode SEEK, permasalahan akan muncul jika nilai sale_date tidak bersifat unik. Oleh karenanya, untuk implementasi berdasarkan SEEK, diperlukan sorting pada kolom bernilai unik, atau mengkombinasikan kolom tidak unik dengan kolom yang memiliki nilai unik. Contoh modifikasi tersebut adalah:

SELECT *
  FROM ( SELECT *
           FROM sales
          WHERE sale_date <= ?
            AND NOT (sale_date = ? AND sale_id >= ?)
          ORDER BY sale_date DESC, sale_id DESC
       )
LIMIT 10

dengan mengasumsikan nilai sale_id adalah bersifat unik. Dengan cara di atas, kita dapat memperoleh nilai row unik untuk digunakan sebagai kursor oleh implementasi SEEK kita.

Oke, dari segi implementasi, OFFSET bisa dikatakan lebih unggul karena relatif lebih mudah untuk diimplementasikan, namun bagaimana dengan segi performanya? Suatu implementasi pagination yang baik seharusnya memiliki waktu pengoperasian query yang konsisten, yakni tidak terpengaruh oleh banyaknya data yang ada di dalam tabel. Jika kita kembali ke contoh query google tadi, performa query yang stabil berarti waktu untuk mendapatkan hasil di page pertama dan hasil di page ke-3547 seharusnya tidaklah berbeda (secara signifikan). Mari kita bandingkan:

Perbandingan Performa SEEK VS OFFSET

Perbandingan Performa SEEK vs OFFSET

Untuk indikator ini, dapat dengan mudah dilihat kelebihan SEEK terhadap OFFSET! Metode SEEK memiliki kecepatan query yang lebih konsisten dikarenakan cara kerjanya yang memanfaatkan seeking dari INDEXED SORTED_COLUMN (tentu saja kita meng-index kolom sales_date bukan?). Sedangkan pada kasus OFFSET, query tersebut tetap "dipaksa" untuk menghitung dan melakukan proses I/O yang cukup menghabiskan resource hingga batas OFFSET yang kita tentukan, dan karenanya mengalami performa hit seiring dengan semakin besarnya nilai OFFSET.

Demikian artikel tentang pagination kali ini, semoga dapat mengguggah minat teman-teman untuk mencari tahu lebih banyak!

Diadaptasi dari: https://use-the-index-luke.com/sql/partial-results/fetch-next-page#sb-row-values