Furkan KapukayaYazılım geliştirme
Backend, API ve Veritabanı2 dk okuma

API'de Sayfalama: Offset mi, Cursor mı?

API ve listelerde sayfalamanın neden gerekli olduğu, offset ve cursor (keyset) sayfalama karşılaştırması, toplam kayıt sayısı, sıralama tutarlılığı, yanıt formatı ve performans ipuçları.

Bir API'nin /siparisler uç noktası tüm siparişleri tek seferde döndürüyorsa, bugün sorun yoktur. İki yıl sonra yüz bin siparişle bu uç nokta hem sunucuyu hem istemciyi kilitler. Sayfalama, büyük listeleri yönetilebilir parçalara bölmenin standart yoludur ve API tasarımının baştan düşünülmesi gereken parçalarındandır.

Offset sayfalama

En bilinen yöntemdir: "20 kayıt atla, sonraki 20'yi ver."

GET /siparisler?sayfa=3&boyut=20
SELECT ... ORDER BY Tarih DESC, Id DESC
OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;

Artıları: Basit, belirli bir sayfaya doğrudan atlanabilir, sayfa numaralı arayüzlerle uyumlu.

Eksileri:

  • Sayfa numarası büyüdükçe yavaşlar; veritabanı atlanan satırları da okur.
  • Listeye yeni kayıt eklenirse kayıtlar kayar: aynı kayıt iki sayfada görünebilir veya bir kayıt hiç görünmeyebilir.

Cursor (keyset) sayfalama

"Son gördüğüm kayıttan sonrakileri ver" mantığıyla çalışır:

GET /siparisler?sonraki=eyJ0IjoiMjAyNi0xMC0wNSIsImlkIjo5ODc2fQ&boyut=20
SELECT TOP 20 ... FROM Siparisler
WHERE (Tarih < @sonTarih) OR (Tarih = @sonTarih AND Id < @sonId)
ORDER BY Tarih DESC, Id DESC;

Artıları: Sayfa ne kadar ileride olursa olsun hızlıdır (doğru indeksle), yeni kayıtlar eklense de kayma olmaz.

Eksileri: Belirli bir sayfa numarasına atlanamaz; sıralama alanları sabit olmalıdır.

Karşılaştırma

OffsetCursor
Uygun arayüzSayfa numaralı tablolar, yönetim panelleriSonsuz kaydırma, mobil, entegrasyonlar
Derin sayfalarda performansKötüleşirSabit
Veri değişirken tutarlılıkKayma olabilirTutarlı
Uygulama kolaylığıKolayOrta

Ortak kurallar

  1. Kararlı sıralama: Sıralamada her zaman benzersiz bir alan (Id) bulunmalıdır; aksi halde aynı tarihli kayıtların sırası sorgudan sorguya değişebilir.
  2. Sayfa boyutu sınırı: İstemci boyut=100000 gönderemesin; makul bir üst sınır koyun.
  3. Toplam sayı dikkatli: COUNT(*) büyük tablolarda pahalıdır. Gerçekten gerekiyorsa ayrı veya isteğe bağlı sunun.
  4. Cursor'ı opak tutun: İçeriği base64 gibi bir biçimde kodlayın; istemci içini yorumlamaya çalışmasın, siz de formatı ileride değiştirebilin.

Yanıt formatı

{
  "veri": [ ... ],
  "sonraki": "eyJ0IjoiMjAyNi0xMC0wNSIsImlkIjo5ODc2fQ",
  "dahaVar": true
}

Tutarlı bir yanıt yapısı, API'yi kullananların işini kolaylaştırır. Hata yanıtları için de benzer bir standart kullanın: Problem Details. API tasarımının diğer temelleri için bkz. REST API.

Sık sorulan sorular

Yönetim panelinde hangisini kullanmalıyım?

Kullanıcılar genellikle ilk birkaç sayfaya bakar ve filtre kullanır; offset sayfalama çoğu panel için yeterlidir.

Entegrasyonlarda tüm veriyi çekmek gerekiyorsa?

Cursor sayfalama veya "şu tarihten sonra değişenler" filtresiyle artımlı senkronizasyon en güvenilir yoldur.

Sonuç

Sayfalama, API'nin bugün değil yıllar sonra da hızlı kalmasını sağlar. Kullanıcı arayüzü için offset, büyük ve sürekli değişen veri ile entegrasyonlar için cursor yaklaşımı genellikle en doğru seçimdir.