Menguasai seni merancang schema warehouse: star schema dengan fact & dimension tables, perbandingan dengan snowflake schema, serta Slowly Changing Dimensions (SCD) tipe 1-3 untuk menangani perubahan data historis, dilengkapi praktik desain schema warehouse end-to-end

Di episode 3 kalian telah mempertajam SQL sebagai bahasa transformasi. Namun query yang cepat tidak akan menyelamatkan schema yang buruk. Data modeling adalah keputusan struktur yang menentukan apakah analyst bisa menjawab pertanyaan bisnis dengan mudah, atau harus menulis query 150 baris untuk hal sederhana.
Mengapa data modeling begitu krusial bagi data engineer? Karena warehouse adalah produk yang kalian jual ke organisasi. Schema yang baik membuat data mudah dimengerti, query cepat, dan perubahan bisnis mudah diakomodasi. Di episode ini kita bedah dua pola dominan (star & snowflake), konsep fact/dimension, dan cara menangani perubahan data historis dengan SCD.
Setiap model analitik tersusun dari dua jenis tabel:
Fact table mencatat peristiwa/kejadian yang diukur — jumlah, harga, durasi. Ciri-cirinya: banyak baris, terus bertambah, dan berisi foreign key ke dimension serta kolom numerik. Contoh: fact_orders dengan order_id, customer_id, product_id, quantity, amount.
Dimension table mencatat konteks/atribut dari sebuah peristiwa — siapa, apa, di mana, kapan. Ciri-cirinya: lebih sedikit baris, kaya atribut deskriptif, dan berubah lambat. Contoh: dim_customer dengan customer_id, name, city, segment.
Aturan praktis: fakta menjawab "berapa" (berapa pesanan? berapa revenue?), dimensi menjawab "menurut apa" (menurut pelanggan? menurut kota? menurut tanggal?).
Star schema menempatkan fact table di tengah, terhubung langsung ke dimension table — bentuknya seperti bintang. Karakteristiknya:
CREATE TABLE dim_customer (
customer_id INT PRIMARY KEY,
name TEXT NOT NULL,
city TEXT,
segment TEXT
);
CREATE TABLE dim_product (
product_id INT PRIMARY KEY,
name TEXT NOT NULL,
category TEXT,
price NUMERIC(12,2)
);
CREATE TABLE fact_orders (
order_id INT PRIMARY KEY,
customer_id INT REFERENCES dim_customer(customer_id),
product_id INT REFERENCES dim_product(product_id),
order_date DATE NOT NULL,
quantity INT NOT NULL,
amount NUMERIC(12,2) NOT NULL
);Keuntungan utama star schema: query analitik hanya perlu beberapa join yang singkat — performa tinggi dan mudah dimengerti.
Snowflake schema menormalisasi dimension table: dim_product dipecah lagi menjadi dim_category, dim_product berisi category_id. Bentuknya seperti kepingan salju.
Di era warehouse kolumnar yang murah dan cepat, star schema hampir selalu menang. Snowflake schema hanya masuk akal jika penghematan storage sangat signifikan — kasus yang semakin jarang. Ini mengapa rekomendasi industri modern: mulai dari star, hindari snowflake kecuali ada alasan kuat.
Masalah klasik data modeling: apa yang terjadi ketika atribut sebuah dimensi berubah? Contoh: pelanggan pindah kota. Apakah laporan historis harus ikut berubah? Ada tiga strategi standar:
| Tipe | Perilaku | Kapan Dipakai |
|---|---|---|
| SCD Type 1 | Timpa nilai lama dengan yang baru | Atribut yang tidak penting untuk historis (mis. nomor telepon) |
| SCD Type 2 | Simpan baris baru + tanggal berlaku, nilai lama dipertahankan | Atribut yang memengaruhi analisis historis (mis. segmen pelanggan) |
| SCD Type 3 | Simpan kolom previous_ untuk perubahan terakhir saja | Butuh "nilai sebelum" saja, tanpa full history |
CREATE TABLE dim_customer_scd2 (
customer_id INT NOT NULL,
name TEXT NOT NULL,
city TEXT,
segment TEXT,
valid_from DATE NOT NULL,
valid_to DATE, -- NULL = versi aktif
is_current BOOLEAN NOT NULL DEFAULT true,
PRIMARY KEY (customer_id, valid_from)
);
-- Pindahkan baris lama ke status non-aktif lalu masukkan baris baru
UPDATE dim_customer_scd2
SET valid_to = CURRENT_DATE, is_current = false
WHERE customer_id = 42 AND is_current;
INSERT INTO dim_customer_scd2 (customer_id, name, city, segment, valid_from, is_current)
SELECT customer_id, name, 'Jakarta', segment, CURRENT_DATE, true
FROM dim_customer_scd2
WHERE customer_id = 42 AND is_current
LIMIT 1;SCD Type 2 adalah standar untuk warehouse serius: ia membuat historis yang akurat — revenue bulan lalu tetap terhitung dengan segmen yang berlaku bulan lalu, bukan segmen hari ini. Banyak tool (dbt, Airbyte) menyediakan helper untuk pola ini, tapi kalian harus paham mekanismenya.
Tip
Rule of thumb SCD: tanyakan "apakah analyst perlu menjawab 'berapa x berdasarkan kondisi yang berlaku saat itu'?" Jika ya, pakai Type 2. Jika atribut hanya untuk konteks saat ini, Type 1 lebih sederhana dan murah.
Mari desain schema untuk studi kasus nyata: platform e-commerce ingin menganalisis penjualan per produk, per kota, dan per bulan.
Langkah 1 — Identifikasi fakta dan dimensi:
fact_sales (sales_id, customer_id, product_id, store_id, date_id, quantity, revenue).dim_customer, dim_product, dim_store, dim_date.Langkah 2 — Desain dim_date yang berperan penting untuk analisis waktu:
CREATE TABLE dim_date (
date_id DATE PRIMARY KEY,
day_of_week TEXT NOT NULL,
month INT NOT NULL,
month_name TEXT NOT NULL,
quarter INT NOT NULL,
year INT NOT NULL,
is_weekend BOOLEAN NOT NULL
);Langkah 3 — Tentukan strategi SCD per dimensi:
dim_product.category → Type 1 (kategori produk jarang penting secara historis).dim_customer.segment → Type 2 (perubahan segmen harus tercermin pada analisis historis).Langkah 4 — Query konsumsi harus sesederhana mungkin:
SELECT
d.month_name,
p.category,
SUM(f.revenue) AS total_revenue
FROM fact_sales f
JOIN dim_date d USING (date_id)
JOIN dim_product p USING (product_id)
GROUP BY d.month_name, p.category
ORDER BY d.month_name;Perhatikan: analyst cukup melakukan join sederhana ke dimensi. Inilah tujuan akhir desain schema — membuat analisis menjadi sepele.
Fact table berisi atribut deskriptif. Nomor pesanan, nama pelanggan, kategori produk — semua harus di dimension, bukan di fact. Fact menyimpan ukuran dan foreign key.
Mengabaikan SCD dan membiarkan nilai berubah. Laporan bulan lalu akan berubah diam-diam saat atribut dimensi di-update — bencana untuk kepercayaan data.
Over-normalisasi (snowflake) tanpa alasan. Setiap join tambahan memperlambat query dan menyulitkan pemahaman. Star dulu, snowflake hanya dengan pembenaran.
Tanpa dim_date lengkap. Analisis waktu (bulan, kuartal, hari libur) akan ditulis ulang terus-menerus oleh semua orang. Satu dimensi tanggal yang baik menyelamatkan banyak duplikasi.
Di episode 4 ini kalian telah menguasai inti data modeling warehouse:
Di episode 5 selanjutnya kita beralih dari SQL ke Python untuk data engineering: pandas & polars untuk transformasi, requests untuk mengambil data dari API, error handling yang benar, dan testing untuk kode data. Sampai jumpa di episode 5!