PostgreSQL Materialized View ile ERP Raporlarını 10x Hızlandırmak

Dashboard raporlarınız çok mu yavaş? Materialized View ile 100.000+ satırlık ERP verilerinden anlık rapor üretmeyi öğrenin. 12 saniye → 0.8 milisaniye.

Sorun: Rapor 12 Saniye Sürüyor

ERP verilerinizi PostgreSQL’e taşıdınız. İlk aylar güzel çalıştı. Sonra veri birikti. 100.000+ satır oldu. Ve artık basit bir rapor sorgusu 12 saniye sürüyor.

Kullanıcı ne yaşıyor? Sayfa açıldı → boş ekran → 12 sn bekleme… → veriler geldi. Kabul edilemez.

Neden Bu Kadar Yavaş?

Her sayfa açılışında PostgreSQL şunu yapıyor:

100.000+ satırın HEPSİNİ tara

Her satırı grupla (şube, ay)

Toplamları hesapla

96 satırlık özet tablo döndür

96 satırlık sonuç için 100.000 satırı taramak israf.

Çözüm: Materialized View

Materialized View (MV), sorgunun sonucunu önceden hesaplayıp saklıyor. Sizden rapor istendiğinde tüm tabloyu taramak yerine, hazır sonucu anında döndürüyor.

Normal sorgu:  Her seferinde 100K satır tara → 12 saniye
MV sorgusu:    Hazır 96 satırı oku → 0.8 milisaniye

150x hızlanma.

Nasıl Yapılır?

1. MV Oluşturma

CREATE MATERIALIZED VIEW mv_aylik_satis AS
SELECT 
    branch AS sube,
    DATE_TRUNC('month', sale_date)::date AS ay,
    SUM(amount) AS toplam_ciro,
    COUNT(*) AS islem_sayisi,
    COUNT(DISTINCT customer_code) AS musteri_sayisi,
    NOW() AS son_guncelleme
FROM sales
WHERE sale_date >= '2023-01-01'
GROUP BY branch, DATE_TRUNC('month', sale_date)::date
WITH DATA;

-- Hızlı sorgulama için index
CREATE INDEX idx_mv_satis ON mv_aylik_satis (sube, ay DESC);

Bu komut çalıştığında, PostgreSQL 100K satırı tarayıp sonucu saklıyor. Artık bu saklanan sonuçtan okuyor.

2. Otomatik Güncelleme

MV’ler kendiliğinden güncellenmez. Düzenli aralıklarla “yenile” demeniz gerekir:

-- Manuel yenileme
REFRESH MATERIALIZED VIEW mv_aylik_satis;

-- Supabase'de otomatik (pg_cron ile):
-- Her sabah 07:00'da yenile
SELECT cron.schedule(
    'satis-rapor-guncelle',
    '0 4 * * *',   -- UTC 04:00 = TR 07:00
    'REFRESH MATERIALIZED VIEW CONCURRENTLY mv_aylik_satis'
);

💡 İpucu: CONCURRENTLY eklerseniz, yenileme sırasında kullanıcılar raporu okumaya devam edebilir. Bunun için unique index gerekir.

3. React’tan Kullanma

MV’yi normal tablo gibi sorgularsınız — hiçbir fark yok:

const { data } = await supabase
  .from('mv_aylik_satis')   // MV'yi tablo gibi sorgula
  .select('*')
  .eq('sube', 'MERKEZ')
  .order('ay', { ascending: false });

Ne Zaman MV Kullanmalı?

DurumMV Kullan?
Dashboard özet tabloları✅ Evet
Aylık/dönemsel raporlar✅ Evet
Anlık stok durumu❌ Hayır (sürekli değişiyor)
Form verileri (kaydetme/silme)❌ Hayır (anında görünmeli)

Temel kural: Sık okunan ama nadir değişen veriler için MV mükemmeldir.

Son Güncelleme Bilgisi

Kullanıcıya “bu veri ne zaman güncellendi?” göstermek güven verir:

Aylık Satış Raporu
┌──────────┬──────┬──────────────┐
│ Şube     │ Ay   │ Toplam Ciro  │
│ Merkez   │ Mart │ ₺1.245.000   │
│ Adana    │ Mart │ ₺987.000     │
└──────────┴──────┴──────────────┘
Son güncelleme: Bugün 07:00

Dikkat Edilecekler

  • MV disk alanı kullanır — verileri fiziksel olarak saklar
  • Supabase’de MV’ler RLS desteklemez — erişim kontrolünü RPC fonksiyonu ile sarmalayın
  • Yenileme süresi — çok büyük tablolarda birkaç dakika sürebilir

Bu Yaklaşım Temel Senaryolar İçin Yeter

Tek bir MV ile dashboard raporlarınız 10x-200x hızlanır. Ama birden fazla MV birbirine bağlıysa (birinin sonucu diğerinin girdisi), yenileme sıralaması ve hata yönetimi karmaşıklaşır.

Biz 6+ bağımlı MV’yi koordine eden bir altyapıyı production’da çalıştırıyoruz. İhtiyacınız olursa deneyimimizden faydalanabilirsiniz.


Bu yazı AstaFlow Case Study serisinin bir parçasıdır.