Add materialized_view_postgresql.MD

This commit is contained in:
mbahsomo 2025-12-31 13:31:17 +00:00
commit 007407631f
1 changed files with 203 additions and 0 deletions

View File

@ -0,0 +1,203 @@
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
```sql
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
```sql
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 filter
* `JOIN` → index kolom join
* `ORDER BY` → index kolom sorting
---
## 2⃣ **UNIQUE INDEX untuk REFRESH CONCURRENTLY**
Tanpa ini, `CONCURRENTLY` **akan error**.
```sql
CREATE UNIQUE INDEX ux_mv_penjualan
ON mv_laporan_penjualan (tanggal, cabang_id);
```
Lalu refresh:
```sql
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:
```sql
(tanggal)
(cabang_id)
```
✅ Lebih optimal:
```sql
CREATE INDEX idx_mv_penjualan_tanggal_cabang
ON mv_laporan_penjualan (tanggal, cabang_id);
```
Urutan kolom **HARUS mengikuti pola query**:
```sql
WHERE tanggal = ?
AND cabang_id = ?
```
---
## 4⃣ **Partial Index untuk Data Populer**
Kalau query sering ambil data terbaru:
```sql
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:
```sql
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**.
```sql
ANALYZE mv_laporan_penjualan;
```
Untuk rutin:
```sql
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:
```sql
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
```sql
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.
```sql
EXPLAIN ANALYZE
SELECT *
FROM mv_laporan_penjualan
WHERE tanggal = '2025-12-01';
```
Cari:
* `Index Scan`
* `Index 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 ANALYZE` hasilmu
* ⏱️ Rekomendasi jadwal refresh (harian/jam)
Kirim saja **struktur MV + contoh query yang sering dipakai**.