3.5 KiB
Berikut strategi performa Materialized View di PostgreSQL (fokus INDEX & refresh) yang sudah terbukti efektif untuk kasus laporan & query berat.
1️⃣ WAJIB: Buat INDEX di Materialized View
Materialized view TIDAK otomatis punya index.
Contoh
CREATE MATERIALIZED VIEW mv_laporan_penjualan AS
SELECT
tanggal,
cabang_id,
SUM(total) AS total_penjualan
FROM penjualan
GROUP BY tanggal, cabang_id;
Index untuk filter & join
CREATE INDEX idx_mv_penjualan_tanggal
ON mv_laporan_penjualan (tanggal);
CREATE INDEX idx_mv_penjualan_cabang
ON mv_laporan_penjualan (cabang_id);
📌 Rule utama
WHERE→ index kolom filterJOIN→ index kolom joinORDER BY→ index kolom sorting
2️⃣ UNIQUE INDEX untuk REFRESH CONCURRENTLY
Tanpa ini, CONCURRENTLY akan error.
CREATE UNIQUE INDEX ux_mv_penjualan
ON mv_laporan_penjualan (tanggal, cabang_id);
Lalu refresh:
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_laporan_penjualan;
🎯 Benefit
- Query tetap bisa baca data
- Tidak lock materialized view
3️⃣ Gunakan Composite Index (bukan banyak index kecil)
❌ Buruk:
(tanggal)
(cabang_id)
✅ Lebih optimal:
CREATE INDEX idx_mv_penjualan_tanggal_cabang
ON mv_laporan_penjualan (tanggal, cabang_id);
Urutan kolom HARUS mengikuti pola query:
WHERE tanggal = ?
AND cabang_id = ?
4️⃣ Partial Index untuk Data Populer
Kalau query sering ambil data terbaru:
CREATE INDEX idx_mv_penjualan_30hari
ON mv_laporan_penjualan (tanggal)
WHERE tanggal >= CURRENT_DATE - INTERVAL '30 days';
⚡ Sangat cepat untuk dashboard “bulan ini”.
5️⃣ Covering Index (INCLUDE)
Agar Index Only Scan terjadi:
CREATE INDEX idx_mv_cover
ON mv_laporan_penjualan (tanggal, cabang_id)
INCLUDE (total_penjualan);
📈 Mengurangi akses ke heap → performa naik.
6️⃣ VACUUM & ANALYZE setelah REFRESH
Materialized view tidak auto-analyze.
ANALYZE mv_laporan_penjualan;
Untuk rutin:
VACUUM ANALYZE mv_laporan_penjualan;
📌 Sangat penting untuk planner memilih index yang benar.
7️⃣ Pisahkan MV untuk Use Case Berbeda
❌ Satu MV dipakai semua kebutuhan ✅ Beberapa MV kecil & spesifik
Contoh:
mv_penjualan_harian
mv_penjualan_bulanan
mv_penjualan_per_cabang
Lebih cepat refresh & index lebih fokus.
8️⃣ Refresh Incremental (Strategi Lanjutan)
PostgreSQL tidak native incremental refresh.
Solusi umum:
- MV hanya data lama
- Data hari ini query langsung tabel
SELECT * FROM mv_penjualan_lama
UNION ALL
SELECT ... FROM penjualan WHERE tanggal = CURRENT_DATE;
⚡ Refresh MV cukup seminggu sekali.
9️⃣ Gunakan EXPLAIN ANALYZE
Pastikan index benar-benar dipakai.
EXPLAIN ANALYZE
SELECT *
FROM mv_laporan_penjualan
WHERE tanggal = '2025-12-01';
Cari:
Index ScanIndex Only Scan
🔥 Checklist Cepat (Best Practice)
✅ Selalu buat index ✅ Buat UNIQUE index jika pakai CONCURRENTLY ✅ Composite index > banyak index kecil ✅ Partial index untuk data populer ✅ ANALYZE setelah refresh ✅ Jangan jadikan MV “tabel serba guna”
Kalau mau, saya bisa:
- ⚙️ Buatkan template index berdasarkan query kamu
- 📊 Analisis
EXPLAIN ANALYZEhasilmu - ⏱️ Rekomendasi jadwal refresh (harian/jam)
Kirim saja struktur MV + contoh query yang sering dipakai.