TL;DR
Fact table nyimpen angka hasil pengukuran dari sebuah proses bisnis, misalnya jumlah unit terjual dan nilai transaksi, plus kunci penghubung ke tabel dimensi. Dimension table nyimpen atribut deskriptif yang jadi konteks angka itu, misalnya nama produk, kategori, cabang, dan tanggal. Susunan satu fact table di tengah yang dikelilingi beberapa dimension table disebut star schema, dan itu bentuk dasar dimensional modeling ala Kimball.
Fact table nyimpen angka yang diukur. Dimension table nyimpen konteks dari angka itu.
Kalimat itu 80 persen dari yang perlu kamu tau. Sisanya soal cara nyusunnya biar query-mu nggak berantakan.
Model ini dipopulerkan Ralph Kimball di awal 1990-an, dan sampai sekarang masih jadi bentuk standar isi gudang data di banyak perusahaan Indonesia. Power BI, Looker Studio, dan Tableau semuanya paling nyaman dikasih data dalam bentuk ini.
Di bawah ini beda keduanya, cara nentuin grain, dan contoh query dari data toko ritel.
Fact table adalah tabel yang nyimpen hasil pengukuran dari satu proses bisnis, misalnya penjualan, pengiriman, atau klaim asuransi. Isinya dua jenis kolom: kolom angka yang bisa dijumlahkan (disebut measure), dan kolom kunci penghubung ke tabel dimensi. Fact table tumbuh cepat, bisa jutaan baris per bulan.
fact_penjualan
-------------------------------
tanggal_key INT -- kunci ke dim_tanggal
produk_key INT -- kunci ke dim_produk
cabang_key INT -- kunci ke dim_cabang
pelanggan_key INT -- kunci ke dim_pelanggan
nomor_struk VARCHAR
jumlah_unit INT -- measure
nilai_transaksi NUMERIC -- measure
nilai_diskon NUMERIC -- measure
Kolom nomor_struk di situ namanya degenerate dimension. Dia keterangan, bukan angka, tapi nggak punya tabel dimensi sendiri karena nggak ada atribut lain yang nempel di nomor struk.
Kesalahan yang paling sering aku temuin di gudang data: kolom persentase disimpan langsung di fact table, lalu dijumlahkan orang di dashboard. Hasilnya angka margin 480 persen.
Dimension table adalah tabel yang nyimpen atribut deskriptif buat memfilter, mengelompokkan, dan memberi label pada angka di fact table. Isinya jawaban dari pertanyaan siapa, apa, di mana, dan kapan. Barisnya jauh lebih sedikit dari fact table, dan kolomnya justru lebih banyak.
dim_produk
-------------------------------
produk_key INT -- surrogate key
kode_produk VARCHAR -- kode dari sistem sumber
nama_produk VARCHAR
kategori VARCHAR
subkategori VARCHAR
merek VARCHAR
satuan VARCHAR
berlaku_dari DATE
berlaku_sampai DATE
baris_aktif BOOLEAN
Dimensi yang bagus itu lebar. Kolom kayak kategori dan merek memang bisa dinormalisasi jadi tabel terpisah, tapi di dimensional modeling itu sengaja nggak dilakukan. Tujuannya biar query cuma butuh satu join.
Surrogate key adalah angka urut yang dibikin gudang data sendiri, terpisah dari kode di sistem sumber. Alasannya: kode sumber bisa berubah, bisa dipakai ulang buat produk lain, dan formatnya sering beda antar sistem.
Manfaat keduanya lebih penting. Dengan surrogate key, kamu bisa nyimpen beberapa versi baris buat entitas yang sama.
| Aspek | Fact table | Dimension table |
|---|---|---|
| Isi kolom | Angka terukur dan kunci penghubung | Keterangan berbentuk teks dan tanggal |
| Jumlah baris | Jutaan, tumbuh tiap hari | Ratusan sampai puluhan ribu |
| Jumlah kolom | Sedikit, biasanya di bawah 20 | Banyak, bisa lebih dari 50 |
| Peran di query | Sumber angka buat SUM dan COUNT | Sumber filter dan GROUP BY |
| Kunci utama | Gabungan beberapa kunci dimensi | Satu surrogate key |
| Perubahan data | Ditambah, jarang diubah | Diperbarui saat atribut berubah |
Patokan cepat: kalau kolomnya masuk akal buat dijumlahkan, itu fact. Kalau kolomnya masuk akal buat ditaruh di dropdown filter, itu dimension. Bacaan lebih lanjut soal aggregate function yang dipakai di fact table ada di glossary.
Grain adalah definisi apa yang diwakili oleh satu baris di fact table. Tulis grain-nya dalam satu kalimat sebelum kamu milih kolom apa pun. Kalimat itu yang nentuin dimensi mana yang boleh nempel dan measure mana yang valid.
Contoh kalimat grain yang jelas:
Kimball nyusun empat langkah perancangan yang urutannya nggak boleh ditukar: pilih proses bisnis, tentukan grain, tentukan dimensi, lalu tentukan fact. Rinciannya ada di daftar teknik dimensional modeling dari Kimball Group.
Kalau grain kamu campur, misalnya sebagian baris level struk dan sebagian level item, semua penjumlahan bakal salah dan susah dilacak penyebabnya.
Star schema adalah susunan satu fact table di tengah yang dikelilingi beberapa dimension table, masing-masing terhubung lewat satu join. Bentuknya kalau digambar mirip bintang. Ini bentuk paling umum dari dimensional modeling karena query-nya pendek dan gampang dibaca orang bisnis.
dim_tanggal
|
dim_produk -- fact_penjualan -- dim_cabang
|
dim_pelanggan
Alternatifnya snowflake schema, di mana dimensi dipecah lagi jadi tabel bertingkat. Misalnya dim_produk dipisah jadi dim_produk, dim_kategori, dan dim_merek. Itu hemat ruang tapi nambah join.
Buat alat BI modern, star schema masih jadi rekomendasi resmi. Microsoft menuliskannya di panduan star schema Power BI.
Query di bawah ini narik omzet dan jumlah struk per kategori produk per bulan buat cabang di Depok.
SELECT
d.tahun,
d.nama_bulan,
p.kategori,
SUM(f.nilai_transaksi) AS omzet,
COUNT(DISTINCT f.nomor_struk) AS jumlah_struk,
SUM(f.jumlah_unit) AS unit_terjual
FROM fact_penjualan f
JOIN dim_tanggal d ON f.tanggal_key = d.tanggal_key
JOIN dim_produk p ON f.produk_key = p.produk_key
JOIN dim_cabang c ON f.cabang_key = c.cabang_key
WHERE d.tahun = 2025
AND c.kota = 'Depok'
GROUP BY d.tahun, d.nama_bulan, p.kategori
ORDER BY omzet DESC;
Perhatikan polanya. Semua SUM datang dari fact table, semua filter dan GROUP BY datang dari dimension table. Pola itu berlaku di hampir semua query gudang data.
Di dataset toko_berkah, produk "Minyak goreng 2L" pindah dari kategori Sembako ke kategori Kebutuhan Dapur pada 1 Juli 2025.
Kalau baris dimensinya cuma ditimpa, seluruh riwayat penjualan produk itu ikut pindah kategori. Omzet Sembako periode Januari sampai Juni yang tadinya Rp 284,6 juta turun jadi Rp 231,9 juta di laporan yang dijalankan ulang bulan Agustus. Selisihnya Rp 52,7 juta, dan angka itu muncul entah dari mana buat orang keuangan.
Penanganan yang benar namanya slowly changing dimension tipe 2. Baris lama nggak dihapus, cuma ditutup masa berlakunya, lalu baris baru ditambahkan dengan surrogate key berbeda.
produk_key | kode | nama | kategori | berlaku_dari | berlaku_sampai | aktif
1042 | 00841 | Minyak goreng 2L | Sembako | 2023-01-01 | 2025-06-30 | false
2317 | 00841 | Minyak goreng 2L | Kebutuhan Dapur | 2025-07-01 | 9999-12-31 | true
Dengan cara ini, transaksi Januari tetap nempel ke produk_key 1042 dan tetap kehitung sebagai Sembako. Laporan lama nggak berubah waktu dijalankan ulang.
Itu alasan utama surrogate key ada. Bukan soal performa, tapi soal laporan yang bisa dipercaya.
Kalau kolomnya masuk akal buat dijumlahkan, itu fact. Kalau kolomnya dipakai buat memfilter dan mengelompokkan, itu dimension. Fact tumbuh cepat tiap hari, dimension tumbuh pelan.
Grain adalah tingkat detail satu baris fact table, misalnya satu item dalam satu struk. Tentukan grain sebelum milih kolom. Grain yang campur bikin semua penjumlahan salah.
Karena kode dari sistem sumber bisa berubah dan dipakai ulang. Surrogate key juga bikin kamu bisa nyimpen beberapa versi baris buat entitas yang sama tanpa bentrok.
Star schema buat mayoritas kasus. Lebih sedikit join, query lebih pendek, dan orang bisnis lebih gampang paham. Snowflake hemat ruang tapi nambah kerumitan.
Masih. Alasan performanya berkurang karena mesin modern sudah cepat, tapi manfaat kejelasan struktur dan penanganan riwayat data tetap sama. Power BI juga masih menyarankan star schema.
Fact table isinya angka yang diukur, dimension table isinya konteks buat memfilter dan mengelompokkan. Tentukan grain dalam satu kalimat sebelum bikin tabelnya, dan pakai surrogate key supaya riwayat perubahan bisa disimpan.
Kalau kamu lagi ngerapikan alur data dari sistem sumber ke gudang data, konsep ETL dan metric yang konsisten bakal sering kepakai berbarengan.
Latihan nulis query star schema kayak contoh di atas bisa kamu kerjakan langsung di NgulikSQL, tanpa perlu pasang database sendiri.
Coba ambil satu laporan yang sering kamu bikin, lalu tulis kalimat grain-nya. Kalau kalimat itu susah dibikin, biasanya laporannya memang lagi nyampur dua level detail.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Kolom waktu isinya angka gede kayak 1704067200 dan bikin bingung? Itu Unix timestamp. Ini cara ngubahnya jadi tanggal beneran di SQL, plus balik lagi.
Data transaksi tersimpan UTC, tapi laporan harus jam WIB. Kalau salah konversi, angka penjualan tengah malam bisa kecatat di tanggal yang salah. Ini cara handle timezone di SQL dengan benar.
Nambah 30 hari ke tanggal invoice, ngurangin sebulan buat cari periode lalu, ngitung selisih hari antar order. Semua itu aritmetika tanggal, dan SQL punya operator INTERVAL buat ngerjainnya.