← Kursa Dön
📄 Text · 25 min

LIMIT ve OFFSET — Sayfalama

Giriş — Her Şeyi Bir Anda Gösterme

Bir e-ticaret sitesinde 50.000 ürün var. Kullanıcı "Ürünler" sayfasına girdiğinde 50.000 ürünü tek seferde gösteremezsin — hem performans hem kullanıcı deneyimi felakete döner. Bunun yerine sayfa sayfa gösterirsin: "Sayfa 1: 1-20 ürün", "Sayfa 2: 21-40 ürün"...

İşte LIMIT ve OFFSET tam olarak bu ihtiyacı karşılar: sorgu sonucundan belirli sayıda satır al ve belirli bir noktadan başla.

🎯 Analoji: Bir kitap okuyorsun. Kitabın tamamını ezberlemiyorsun — sadece açtığın sayfayı okuyorsun. LIMIT kaç satır (paragraf) okuyacağını, OFFSET hangi sayfadan başlayacağını belirler.


LIMIT — Kaç Satır İstiyorsun?

-- İlk 5 ürünü getir
SELECT product_name, price 
FROM products 
LIMIT 5;

-- En pahalı 3 ürünü getir
SELECT product_name, price 
FROM products 
ORDER BY price DESC 
LIMIT 3;
+-------------------+----------+
| product_name      | price    |
+-------------------+----------+
| iPhone 15 Pro     | 64999.99 |
| MacBook Pro 14"   | 54999.99 |
| Samsung Galaxy S24| 44999.99 |
+-------------------+----------+

LIMIT Olmadan ve İle Performans Farkı

-- ❌ 50.000 satırın hepsini çeker — yavaş, gereksiz bellek kullanımı
SELECT * FROM products ORDER BY price DESC;

-- ✅ Sadece ilk 10 satırı çeker — hızlı, az bellek
SELECT * FROM products ORDER BY price DESC LIMIT 10;

💡 İpucu: Sorgu sonuçlarını sınırlamak hem veritabanı sunucusunu hem ağ trafiğini hem uygulamayı rahatlatır. Özellikle büyük tablolarda her zaman LIMIT kullan.


OFFSET — Nereden Başlayacaksın?

OFFSET, sonuç setinin başından kaç satır atlayacağını belirler:

-- İlk 10 ürünü atla, sonraki 10'u getir (Sayfa 2)
SELECT product_name, price 
FROM products 
ORDER BY product_id 
LIMIT 10 OFFSET 10;

-- Alternatif syntax (LIMIT offset, count)
SELECT product_name, price 
FROM products 
ORDER BY product_id 
LIMIT 10, 10;  -- İlk 10'u atla, sonraki 10'u getir

⚠️ Dikkat: İki syntax'ın parametre sırası ters: - LIMIT 10 OFFSET 20 → 20 satır atla, 10 satır getir - LIMIT 20, 10 → 20 satır atla, 10 satır getir LIMIT ... OFFSET ... formatı daha okunabilir ve hata yapma riski düşük — bunu tercih et.


Pagination (Sayfalama) Uygulaması

Temel Sayfalama Formülü

OFFSET = (sayfa_numarasi - 1) * sayfa_basina_kayit
LIMIT  = sayfa_basina_kayit
-- Sayfa başına 10 ürün

-- Sayfa 1: OFFSET 0, LIMIT 10
SELECT * FROM products ORDER BY product_id LIMIT 10 OFFSET 0;

-- Sayfa 2: OFFSET 10, LIMIT 10
SELECT * FROM products ORDER BY product_id LIMIT 10 OFFSET 10;

-- Sayfa 3: OFFSET 20, LIMIT 10
SELECT * FROM products ORDER BY product_id LIMIT 10 OFFSET 20;

-- Sayfa N: OFFSET (N-1)*10, LIMIT 10

Toplam Sayfa Sayısını Hesaplama

-- Toplam ürün sayısı
SELECT COUNT(*) AS total_products FROM products WHERE is_active = TRUE;
-- Sonuç: 15

-- Sayfa başına 10 ürün → 15 / 10 = 1.5 → 2 sayfa
-- CEIL fonksiyonu yukarı yuvarlar
SELECT CEIL(COUNT(*) / 10.0) AS total_pages 
FROM products 
WHERE is_active = TRUE;
-- Sonuç: 2

Gerçek Dünya Pagination Sorgusu

-- E-ticaret ürün listesi — Sayfa 2, sayfa başına 12 ürün
-- Fiyata göre artan sıralama, sadece aktif ve stokta olan ürünler

SELECT 
    p.product_id,
    p.product_name,
    p.price,
    p.stock_quantity,
    c.category_name
FROM products p
LEFT JOIN categories c ON p.category_id = c.category_id
WHERE p.is_active = TRUE 
  AND p.stock_quantity > 0
ORDER BY p.price ASC
LIMIT 12 OFFSET 12;  -- Sayfa 2

-- Toplam sonuç sayısı (pagination bilgisi için)
SELECT COUNT(*) AS total_results
FROM products
WHERE is_active = TRUE AND stock_quantity > 0;

OFFSET Pagination'ın Performans Sorunu

OFFSET büyüdükçe performans düşer — çünkü veritabanı atlanan satırları da okumak zorundadır:

-- Sayfa 1: Hızlı ✅
SELECT * FROM products ORDER BY product_id LIMIT 20 OFFSET 0;

-- Sayfa 100: Yavaşlamaya başlar ⚠️
SELECT * FROM products ORDER BY product_id LIMIT 20 OFFSET 1980;
-- MySQL 1980 satırı okuyup atar, sonraki 20'yi döndürür

-- Sayfa 5000: Çok yavaş ❌
SELECT * FROM products ORDER BY product_id LIMIT 20 OFFSET 99980;
-- 99980 satır okunup atılır — büyük israf!

Bu sorun büyük tablolarda (100K+ satır) ciddi performans etkisi yapar.

Çözüm: Cursor-Based Pagination (Keyset Pagination)

OFFSET yerine son görülen kaydın ID'sini kullan:

-- İlk sayfa: Son product_id bilgisi yok
SELECT * FROM products 
WHERE is_active = TRUE
ORDER BY product_id ASC 
LIMIT 20;
-- Son satırın product_id'si: 20

-- İkinci sayfa: product_id > 20 olanları getir
SELECT * FROM products 
WHERE is_active = TRUE AND product_id > 20
ORDER BY product_id ASC 
LIMIT 20;
-- Son satırın product_id'si: 40

-- Üçüncü sayfa: product_id > 40
SELECT * FROM products 
WHERE is_active = TRUE AND product_id > 40
ORDER BY product_id ASC 
LIMIT 20;

Keyset pagination avantajları:

  • OFFSET kullanmadığı için her zaman hızlı (hangi "sayfa" olursa olsun)

  • Primary key index'ini kullanır

  • Arada veri eklenip silinse bile tutarlı sonuç verir

Keyset pagination dezavantajları:

  • "Sayfa 57'ye atla" yapılamaz (sıralı ilerlemek gerekir)

  • Birden fazla sütuna göre sıralamada karmaşıklaşır

  • "Toplam sayfa sayısı" bilgisi ayrıca hesaplanmalı

💡 İpucu: - Az sayfa (100'den az) ve "sayfaya atla" gerekiyorsa → OFFSET pagination - Çok sayfa (sonsuz scroll, API'ler) → Keyset pagination - Instagram, Twitter, Facebook gibi uygulamalar keyset pagination kullanır


LIMIT ile Tek Satır Alma

-- En pahalı ürün
SELECT product_name, price 
FROM products 
ORDER BY price DESC 
LIMIT 1;

-- En yeni sipariş
SELECT * FROM orders ORDER BY order_date DESC LIMIT 1;

-- Rastgele bir müşteri
SELECT * FROM customers ORDER BY RAND() LIMIT 1;
-- ⚠️ ORDER BY RAND() büyük tablolarda ÇOK yavaştır!

Rastgele Kayıt Alma — Performanslı Yol

-- ❌ Yavaş — tüm tabloyu sıralar
SELECT * FROM products ORDER BY RAND() LIMIT 5;

-- ✅ Hızlı — ID aralığından rastgele seç
SELECT * FROM products 
WHERE product_id >= (
    SELECT FLOOR(RAND() * (SELECT MAX(product_id) FROM products))
)
ORDER BY product_id 
LIMIT 5;

LIMIT ve UPDATE/DELETE

LIMIT sadece SELECT'te değil, UPDATE ve DELETE'te de kullanılabilir:

-- En eski 100 log kaydını sil
DELETE FROM activity_logs 
ORDER BY created_at ASC 
LIMIT 100;

-- İlk 10 bekleyen siparişi işleme al
UPDATE orders 
SET status = 'processing' 
WHERE status = 'pending' 
ORDER BY order_date ASC 
LIMIT 10;

Gerçek Dünya Örneği — Tam Pagination Sistemi

-- Parametreler (uygulama katmanından gelir)
SET @page = 2;           -- İstenen sayfa
SET @per_page = 12;      -- Sayfa başına kayıt
SET @offset = (@page - 1) * @per_page;

-- Ana sorgu — sayfa verileri
SELECT 
    p.product_id,
    p.product_name,
    p.price,
    c.category_name,
    p.stock_quantity
FROM products p
LEFT JOIN categories c ON p.category_id = c.category_id
WHERE p.is_active = TRUE AND p.stock_quantity > 0
ORDER BY p.created_at DESC
LIMIT 12 OFFSET 12;  -- @per_page OFFSET @offset

-- Meta sorgu — pagination bilgisi
SELECT 
    COUNT(*) AS total_items,
    CEIL(COUNT(*) / 12.0) AS total_pages,
    2 AS current_page,   -- @page
    12 AS per_page        -- @per_page
FROM products
WHERE is_active = TRUE AND stock_quantity > 0;

Sıkça Yapılan Hatalar

  1. ORDER BY olmadan LIMIT kullanmak: SELECT * FROM products LIMIT 10 her çalıştırmada farklı sonuçlar verebilir. LIMIT ile birlikte her zaman ORDER BY kullan.

  2. LIMIT syntax sırasını karıştırmak: LIMIT 10, 20 → "10 atla, 20 getir". Ama çoğu insan "10 getir, 20 atla" olarak okur. LIMIT 20 OFFSET 10 formatı çok daha açık.

  3. Büyük OFFSET değerleri: Sayfa 1000 için OFFSET 20000 kullanmak performansı öldürür. Büyük veri setlerinde keyset pagination kullan.

  4. Toplam sayfa sayısını ayrı sorgulamayı unutmak: Kullanıcıya "Sayfa 2/157" göstermek istiyorsan COUNT(*) sorgusu da gerekir. Bu ek sorgunun maliyetini göz ardı etme.

  5. OFFSET ile veri kayması: Sayfa 1'i görürken yeni kayıt eklenirse, sayfa 2'de aynı kaydı tekrar görebilirsin. Keyset pagination bu sorunu çözer.


Özet

  • LIMIT N sonuç setinden N satır döndürür

  • OFFSET M ilk M satırı atlar

  • Sayfalama formülü: OFFSET = (sayfa - 1) * sayfa_başına, LIMIT = sayfa_başına

  • ORDER BY olmadan LIMIT kullanma — sonuçlar tutarsız olabilir

  • Büyük OFFSET'lerde performans düşer → keyset pagination tercih et

  • LIMIT 20 OFFSET 10 formatı LIMIT 10, 20'den daha okunabilir

  • LIMIT, UPDATE ve DELETE'te de kullanılabilir

  • Toplam sayfa sayısı için ayrı bir COUNT(*) sorgusu gerekir