# PostgreSQL’de Grup Başına En İyi N Kayıt Nasıl Seçilir?
PostgreSQL veritabanınızda, her grup için en iyi N kaydı nasıl seçersiniz? Örneğin, her müşteri için en yüksek satış değerine sahip N siparişi veya her ürün için en son N yorumu nasıl listeleyebilirsiniz? Bu makale, PostgreSQL’de grup başına en iyi N kaydı seçme konusunda adım adım bir rehber sunacak, gerçek dünya örnekleri ve performans optimizasyon teknikleriyle zenginleştirilmiş bir öğrenme yol haritası sunacaktır. Başlangıç seviyesinden ileri seviyeye kadar, PostgreSQL’in gücünden faydalanarak verilerinizi etkili bir şekilde sorgulamayı öğreneceksiniz.
Temel Kavramlar: Pencere Fonksiyonları ve Sıralamalar
PostgreSQL’de grup başına en iyi N kaydı seçmek için pencere fonksiyonlarını ve ORDER BY ile LIMIT ifadelerini birlikte kullanırız. Pencere fonksiyonları, bir veri kümesinin alt kümeleri üzerinde işlem yapmamızı sağlar; bu alt kümeler “pencereler” olarak adlandırılır. ROW_NUMBER() fonksiyonu, her satıra sıralı bir numara atar ve bu sayede en iyi N kaydı kolayca seçebiliriz. RANK(), DENSE_RANK() gibi diğer pencere fonksiyonları da farklı sıralama senaryoları için kullanılabilir. Bu fonksiyonlar, PARTITION BY ifadesiyle gruplandırma işlemini sağlar.
Yeni Başlayanlar İçin Adım Adım Kılavuz: Basit Örnek
Öncelikle basit bir örnek ile başlayalım. urunler adlı bir tablomuz olsun ve bu tabloda urun_adi, fiyat ve kategori sütunları bulunsun. Her kategoride en pahalı iki ürünü seçmek istiyoruz:
SELECT urun_adi, fiyat, kategori
FROM (
SELECT urun_adi, fiyat, kategori,
ROW_NUMBER() OVER (PARTITION BY kategori ORDER BY fiyat DESC) as sıra
FROM urunler
) as ranked_urunler
WHERE sıra <= 2;
Bu sorgu öncelikle alt sorgu ile her kategori için ürünleri fiyatlarına göre azalan sırada sıralar ve ROW_NUMBER() fonksiyonu ile her ürüne bir sıra numarası atar. Dış sorgu ise sadece sıra numarası 2 veya daha küçük olan ürünleri seçer, böylece her kategoride en pahalı iki ürünü elde ederiz.
Orta Seviye: Gerçek Dünya Örneği ve Optimizasyon İpuçları
Şimdi daha gerçekçi bir senaryo ele alalım. siparisler adlı bir tablomuz olsun ve bu tabloda musteri_id, siparis_tarihi, toplam_tutar sütunları bulunsun. Her müşteri için son üç sipariş tarihini bulmak istiyoruz:
SELECT musteri_id, siparis_tarihi, toplam_tutar
FROM (
SELECT musteri_id, siparis_tarihi, toplam_tutar,
ROW_NUMBER() OVER (PARTITION BY musteri_id ORDER BY siparis_tarihi DESC) as sıra
FROM siparisler
) as ranked_siparisler
WHERE sıra <= 3;
Bu sorgu, önceki örneğe benzer şekilde çalışır, ancak ORDER BY kriteri siparis_tarihi olarak değiştirilmiştir. Optimizasyon için, siparisler tablosunda musteri_id ve siparis_tarihi sütunlarına indeks eklemek performansı önemli ölçüde artıracaktır. Bu, PostgreSQL’in verileri daha hızlı filtrelemesini sağlar. İndeksleme konusunda daha fazla bilgi için [fatihsoysal.com](https://fatihsoysal.com) adresini ziyaret edebilirsiniz.
İleri Düzey: Performans Analizi ve Edge Case’ler
Çok büyük veri kümeleriyle çalışırken, performans kritik öneme sahiptir. Yukarıdaki sorguların performansını analiz etmek için EXPLAIN ANALYZE komutunu kullanabilirsiniz. Bu komut, sorgunun yürütülme planını ve her adımın ne kadar sürdüğünü gösterir. Performansı iyileştirmek için aşağıdaki teknikleri deneyebilirsiniz:
* İndeksleme: PARTITION BY ve ORDER BY kriterlerinde kullanılan sütunlara indeks ekleyin.
* Materyalize Görünümler: Sık kullanılan sorgular için materyalize görünümler oluşturun. Bu, önceden hesaplanmış sonuçları saklayarak sorgu süresini kısaltır.
* Parçalama: Çok büyük tabloları daha küçük parçalara bölerek sorgu performansını artırabilirsiniz.
Edge Case’ler:
* Eşit Sıralamalar: ROW_NUMBER() her satıra benzersiz bir sıra numarası atar. Eğer birden fazla satır aynı sıraya sahipse, RANK() veya DENSE_RANK() fonksiyonlarını kullanmayı düşünebilirsiniz. RANK() aynı sıradaki satırlara aynı sıra numarasını atarken, DENSE_RANK() sıra numaralarında boşluk bırakmaz.
* Boş Gruplar: Bazı grupların N’den az kaydı olabilir. Bu durumda, tüm kayıtlar seçilecektir.
Nasıl Daha Karmaşık Koşullar Eklenir?
Yukarıdaki örnekler basit koşullar içerir. Ancak, WHERE cümlesine ek koşullar ekleyerek daha karmaşık sorgular oluşturabilirsiniz. Örneğin, sadece belirli bir tarih aralığındaki siparişleri içeren bir sorgu yazabilirsiniz:
SELECT musteri_id, siparis_tarihi, toplam_tutar
FROM (
SELECT musteri_id, siparis_tarihi, toplam_tutar,
ROW_NUMBER() OVER (PARTITION BY musteri_id ORDER BY siparis_tarihi DESC) as sıra
FROM siparisler
WHERE siparis_tarihi BETWEEN '2023-01-01' AND '2023-12-31'
) as ranked_siparisler
WHERE sıra <= 3;
Bu, belirtilen tarih aralığında her müşteri için son üç siparişi seçer.
PostgreSQL’de Grup Başına Top N Kaydı Seçmek İçin Alternatif Yöntemler
Pencere fonksiyonları en yaygın ve genellikle en verimli yöntem olsa da, grup başına en iyi N kaydı seçmek için başka yöntemler de mevcuttur. Bunlardan biri, alt sorgular kullanarak her grup için ayrı ayrı LIMIT uygulamak olabilir. Ancak, bu yöntem büyük veri kümeleri için pencere fonksiyonlarından daha yavaş olabilir.
Sonuç
Bu makale, PostgreSQL’de grup başına en iyi N kaydı seçmek için çeşitli teknikleri ele aldı. Basit örneklerden karmaşık senaryolara kadar, adım adım bir yaklaşım izleyerek, hem yeni başlayanların hem de deneyimli kullanıcıların bu konuda uzmanlaşmasına yardımcı olmayı amaçladık. Performans optimizasyonu ve edge case’ler üzerinde durarak, verilerinizden en iyi şekilde faydalanmanızı sağladık. Unutmayın, veritabanınızın yapısı ve veri miktarına göre en uygun yöntemi seçmek önemlidir. Sorularınız ve yorumlarınız için [fatihsoysal.com](https://fatihsoysal.com) adresini ziyaret edebilirsiniz.
Sıkça Sorulan Sorular:
1. ROW_NUMBER(), RANK() ve DENSE_RANK() arasındaki fark nedir? ROW_NUMBER() her satıra benzersiz bir sıra numarası atar. RANK() aynı sıradaki satırlara aynı sıra numarasını atar. DENSE_RANK() ise aynı sıradaki satırlara ardışık sıra numaraları atar, boşluk bırakmaz.
2. Çok büyük tablolar için performansı nasıl iyileştirebilirim? İndeksleme, materyalize görünümler ve parçalama tekniklerini kullanabilirsiniz.
3. PARTITION BY ifadesi ne işe yarar? PARTITION BY ifadesi, pencere fonksiyonlarının hangi veri alt kümeleri üzerinde işlem yapacağını belirler. Her grup için ayrı bir sıralama yapmamızı sağlar.
4. ORDER BY ifadesi neden önemlidir? ORDER BY ifadesi, pencere fonksiyonlarının hangi kritere göre sıralama yapacağını belirler. En iyi N kaydı seçmek için doğru sıralama kriterini seçmek şarttır.
5. Alternatif yöntemler var mı? Evet, alt sorgular kullanarak her grup için ayrı ayrı LIMIT uygulamak da mümkündür, ancak büyük veri kümeleri için pencere fonksiyonları genellikle daha verimlidir.
Yazar: Fatih Soysal
