Fact Table vs Dimension Table: Dasar Dimensional Modeling Kimball
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.
Apa itu fact table?
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.
Tiga jenis measure
- Additive. Bisa dijumlah di semua dimensi. Nilai transaksi bisa dijumlah per hari, per cabang, per produk, hasilnya tetap benar.
- Semi additive. Bisa dijumlah di sebagian dimensi. Saldo rekening boleh dijumlah antar nasabah, tapi nggak boleh dijumlah antar tanggal.
- Non additive. Nggak boleh dijumlah sama sekali. Persentase margin dan rasio itu contohnya. Simpan pembilang dan penyebutnya terpisah, lalu hitung rasionya di lapisan laporan.
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.
Apa itu dimension table?
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.
Kenapa pakai surrogate key?
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.
Apa bedanya fact table dan dimension table?
| 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.
Gimana cara nentuin grain fact table?
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:
- "Satu baris sama dengan satu item produk dalam satu struk penjualan."
- "Satu baris sama dengan posisi stok satu produk di satu gudang pada akhir hari."
- "Satu baris sama dengan satu tiket keluhan pelanggan pada saat ditutup."
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.
Apa itu star schema?
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.
Contoh query: omzet per kategori dari star schema
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.
Contoh kasus: laporan yang beda gara-gara satu baris dimensi
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.
FAQ
Gimana cara cepat bedain fact dan dimension?
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.
Apa itu grain dan kenapa penting?
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.
Kenapa dimension pakai surrogate key?
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 atau snowflake?
Star schema buat mayoritas kasus. Lebih sedikit join, query lebih pendek, dan orang bisnis lebih gampang paham. Snowflake hemat ruang tapi nambah kerumitan.
Model Kimball masih relevan?
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.
Ringkasnya
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.
Artikel terkait
Cara Membuat Pivot Dinamis di SQL (Panduan 2026)
Pivot dinamis di SQL ngubah baris jadi kolom tanpa kamu hardcode nama kolomnya. Ini cara bikinnya pakai CASE WHEN dan versi yang kolomnya ngikut data.
Menghitung YTD, QTD, dan MTD di SQL (Panduan 2026)
YTD, QTD, dan MTD ngukur total dari awal tahun, kuartal, atau bulan sampai hari ini. Ini cara ngitungnya di SQL pakai DATE_TRUNC, plus satu query gabungan.
Gap and Island Analysis di SQL
Gap and island analysis di SQL nyari deret data yang berturut-turut (island) dan celah yang bolong (gap). Cocok buat hitung streak login atau cari tanggal transaksi yang hilang.