Kebutuhan analitik pada Bagian 1 kini kita turunkan menjadi model data konkret. Star schema dipilih karena seluruh pertanyaan bisnis berbentuk agregasi yang dipotong menurut beberapa atribut, pola yang paling nyaman dilayani tabel fakta di tengah dan tabel dimensi di sekelilingnya, seperti dibahas pada chapter Star Schema dan Fact Table dan Dimension Table. Hasil bagian ini adalah spesifikasi lima tabel yang menjadi acuan seluruh kode pada bagian berikutnya. Kita tidak menulis kode pemuatan apa pun dulu; perubahan pada tahap desain jauh lebih murah daripada setelah pipeline berjalan.

Diagram Star Schema #

Empat garis relasi membaca fakta ke dimensi: satu baris pesanan terjadi pada tepat satu tanggal, dilakukan tepat satu pelanggan (versi tertentu), memuat tepat satu produk, dan terjadi di tepat satu toko. Tidak ada tabel jembatan dan tidak ada dimensi bersarang; kebutuhan kita memang selesai pada bentuk bintang sederhana ini. Model alternatif snowflake seperti pada chapter Snowflake Schema akan memecah dim_produk menjadi tabel kategori terpisah, tetapi kardinalitas kategori kita hanya empat sehingga pemecahan hanya menambah join tanpa menghemat penyimpanan berarti.

Spesifikasi dim_pelanggan #

KolomTipeKeterangan
pelanggan_skINTEGERsurrogate key, lihat chapter Surrogate Key
nk_hashVARCHARmd5 dari pelanggan_id, pelacak natural key
attr_hashVARCHARmd5 gabungan atribut, pendeteksi perubahan
pelanggan_idVARCHARnatural key dari sistem operasional
nama, emailVARCHARatribut deskriptif
kota, segmenVARCHARatribut analitik yang bisa berubah
valid_from, valid_toDATEmasa berlaku versi (SCD Type 2)
is_currentBOOLEANpenanda versi terkini

Kolom valid_from, valid_to, dan is_current disiapkan sejak awal meski baru dimanfaatkan pada Bagian 6. Menambahkan kolom ini di kemudian hari pada tabel yang sudah berisi fakta berarti menulis ulang sejarah; menyiapkannya sejak awal hampir tanpa biaya.

Spesifikasi fact_pesanan #

KolomTipeKeterangan
pesanan_idVARCHARdegenerate dimension: nomor pesanan tanpa tabel dimensi
barisINTEGERnomor baris pesanan, pembeda grain
tanggal_sk, pelanggan_sk, produk_sk, toko_skINTEGERforeign key ke dimensi
jumlahINTEGERbanyaknya item
harga_satuanBIGINTharga transaksi, bukan harga master
diskonBIGINTpotongan rupiah pada baris pesanan
totalBIGINTjumlah * harga_satuan - diskon
statusVARCHARselesai, dibatalkan, dikembalikan

pesanan_id dan baris disebut degenerate dimension karena berperan sebagai kunci analitis, misalnya menghitung pesanan unik, tetapi tidak memiliki tabel dimensi sendiri. Menyimpan nomor pesanan langsung pada fact table adalah praktik standar Kimball untuk dimensi berumur satu transaksi.

Klasifikasi Measure #

Tiga measure bersifat additive dan boleh dijumlahkan pada semua dimensi. Satu measure tidak:

KolomSifatAlasan
jumlahadditivemenjumlah item lintas dimensi bermakna
totaladditivemenjumlah nilai rupiah bermakna
diskonadditivemenjumlah potongan bermakna
harga_satuannon-additiverata-rata atau nilai tunggal saja; menjumlah harga satuan menghasilkan angka tanpa makna

Klasifikasi ini menentukan ekspresi metrik pada Bagian 1: GMV memakai SUM(total), bukan SUM(harga_satuan) * SUM(jumlah), karena total sudah menyimpan hasil kali per baris termasuk diskon.

Keputusan Kunci pada Desain #

Tiga keputusan lain kita kunci bersama-sama. Pertama, dim_tanggal memakai smart key YYYYMMDD berbentuk INTEGER sehingga rentang tanggal dapat disaring tanpa join, misalnya tanggal_sk BETWEEN 20250301 AND 20250331. Kedua, seluruh dimensi lain memakai surrogate key INTEGER yang diterbitkan oleh pipeline, bukan kunci bisnis dari sistem sumber, agar perubahan pada sistem sumber tidak merusak relasi fakta. Ketiga, gudang data ini tidak memasang constraint PRIMARY KEY maupun FOREIGN KEY pada DuckDB; integritas dijaga pemeriksaan kualitas data pada Bagian 7, mengikuti praktik umum gudang data yang mengutamakan kecepatan pemuatan.

Spesifikasi lima tabel telah lengkap. Pada Bagian 3 kita mulai menulis kode: tabel dimensi pertama beserta mekanisme surrogate key dan pelacakan hash.