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:
CONCURRENTLYeklerseniz, 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ı?
| Durum | MV 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.