Empat langkah Kimball pada chapter sebelumnya menghasilkan daftar dimensi dan fakta, tetapi belum berupa tabel. Star schema adalah wujud nyatanya: satu fact table berada di tengah, dikelilingi dimension table yang masing-masing terhubung langsung ke fact melalui satu foreign key — bentuk yang menyerupai bintang bila digambar. Struktur sederhana tersebut menjadi standar de-facto warehouse karena query analitik menjadi pendek, cepat, dan mudah dipahami pengguna bisnis. Pada chapter ini kita membangun star schema lengkap untuk toko online kita, mengisinya dengan data pesanan Budi, Siti, dan Dewi, lalu mengujinya dengan query analitik nyata.
Struktur Bintang #
Pada star schema, fact table hanya menyimpan kunci penghubung dan measure numerik; seluruh atribut deskriptif (nama pelanggan, kategori produk, bulan) tinggal di dimension table. Setiap dimensi terhubung ke fact dalam satu lapis — tidak ada dimensi yang menumpuk pada dimensi lain:
Membangun Star Schema Toko Online #
Grain fact table kita: satu baris = satu item produk dalam satu pesanan. Empat dimensi memotong fact tersebut: waktu, pelanggan, produk, dan toko. Berikut DDL lengkapnya, diuji nyata dengan SQLite melalui modul sqlite3 Python sesuai dokumentasi SQLite
:
CREATE TABLE dim_waktu (
waktu_id INTEGER PRIMARY KEY,
tanggal TEXT NOT NULL,
bulan TEXT NOT NULL,
kuartal TEXT NOT NULL
);
CREATE TABLE dim_pelanggan (
pelanggan_id INTEGER PRIMARY KEY,
nama TEXT NOT NULL,
kota TEXT NOT NULL,
segmen TEXT NOT NULL
);
CREATE TABLE dim_produk (
produk_id INTEGER PRIMARY KEY,
nama TEXT NOT NULL,
kategori TEXT NOT NULL,
harga INTEGER NOT NULL
);
CREATE TABLE dim_toko (
toko_id INTEGER PRIMARY KEY,
nama_toko TEXT NOT NULL,
kota TEXT NOT NULL
);
CREATE TABLE fact_pesanan (
waktu_id INTEGER NOT NULL REFERENCES dim_waktu(waktu_id),
pelanggan_id INTEGER NOT NULL REFERENCES dim_pelanggan(pelanggan_id),
produk_id INTEGER NOT NULL REFERENCES dim_produk(produk_id),
toko_id INTEGER NOT NULL REFERENCES dim_toko(toko_id),
qty INTEGER NOT NULL,
jumlah INTEGER NOT NULL
);Perhatikan polanya: kolom fact_pesanan terdiri atas empat foreign key plus dua measure (qty, jumlah), tanpa satu pun atribut deskriptif. Data contoh kita muat sebagai berikut:
INSERT INTO dim_waktu VALUES
(20250110, '2025-01-10', 'Januari', 'Q1'),
(20250115, '2025-01-15', 'Januari', 'Q1'),
(20250205, '2025-02-05', 'Februari', 'Q1'),
(20250220, '2025-02-20', 'Februari', 'Q1'),
(20250308, '2025-03-08', 'Maret', 'Q1'),
(20250318, '2025-03-18', 'Maret', 'Q1');
INSERT INTO dim_pelanggan VALUES
(1, 'Budi', 'Jakarta', 'Reguler'),
(2, 'Siti', 'Bandung', 'Reguler'),
(3, 'Dewi', 'Surabaya', 'Premium');
INSERT INTO dim_produk VALUES
(1, 'Mouse Wireless M10', 'Aksesoris', 150000),
(2, 'Keyboard Mekanik K75', 'Aksesoris', 450000),
(3, 'Monitor 24 Inci IPS', 'Monitor', 1200000);
INSERT INTO dim_toko VALUES
(1, 'TokoKita Pusat', 'Jakarta'),
(2, 'TokoKita Bandung', 'Bandung');
INSERT INTO fact_pesanan VALUES
(20250110, 1, 1, 1, 2, 300000),
(20250110, 1, 3, 1, 1, 1200000),
(20250115, 2, 2, 2, 1, 450000),
(20250205, 3, 2, 1, 1, 450000),
(20250220, 1, 1, 2, 2, 300000),
(20250308, 2, 3, 1, 1, 1200000),
(20250318, 3, 1, 2, 2, 300000);Identifier waktu_id memakai format YYYYMMDD sehingga urutan angka cocok dengan urutan kalender — trik sederhana yang membuat pemfilteran rentang tanggal tetap cepat.
Query Analitik pada Star Schema #
Pertanyaan bisnis pertama: berapa pendapatan per bulan per kota toko? Cukup join fact dengan dua dimensi yang dibutuhkan:
SELECT w.bulan, t.kota AS kota_toko,
SUM(f.jumlah) AS pendapatan,
COUNT(*) AS jumlah_baris
FROM fact_pesanan f
JOIN dim_waktu w ON w.waktu_id = f.waktu_id
JOIN dim_toko t ON t.toko_id = f.toko_id
GROUP BY w.bulan, t.kota
ORDER BY MIN(f.waktu_id), t.kota;Output yang Dihasilkan:
Januari | Jakarta | 1500000 | 2
Januari | Bandung | 450000 | 1
Februari | Jakarta | 450000 | 1
Februari | Bandung | 300000 | 1
Maret | Jakarta | 1200000 | 1
Maret | Bandung | 300000 | 1Mari kita telaah baris-baris kode di atas:
- Baris 1 (
SELECT w.bulan, t.kota ...): atribut deskriptif langsung tersedia dari dimensi — tanpa subquery, tanpa join bertingkat. - Baris 5-6 (dua
JOIN): hanya dimensi yang relevan yang ikut —dim_pelanggandandim_produktidak perlu digabung untuk pertanyaan ini. - Baris 7 (
GROUP BY w.bulan, t.kota): pemotongan analisis mengikuti kombinasi atribut dimensi. - Baris 8 (
ORDER BY MIN(f.waktu_id)): bulan diurutkan mengikuti tanggal terkecil di tiap grup agar hasil tampil urut secara kalender, bukan urut abjad nama bulan.
Pertanyaan kedua membuktikan fleksibilitas yang sama ke arah lain — total belanja per pelanggan hanya butuh satu join:
SELECT p.nama, p.segmen, SUM(f.jumlah) AS total_belanja
FROM fact_pesanan f
JOIN dim_pelanggan p ON p.pelanggan_id = f.pelanggan_id
GROUP BY p.nama, p.segmen
ORDER BY total_belanja DESC;Output yang Dihasilkan:
Budi | Reguler | 1800000
Siti | Reguler | 1650000
Dewi | Premium | 750000Kelebihan Star Schema #
Keunggulan pertama adalah join yang sederhana: setiap dimensi tepat satu lapis dari fact, sehingga query analitik tidak pernah merangkai rantai join panjang seperti pada skema 3NF. Keunggulan kedua adalah performa: engine seperti DuckDB mengoptimalkan pola join fact-ke-dimensi secara khusus, dan dimension table yang kecil mudah dimuat penuh ke memori. Keunggulan ketiga adalah keterbacaan — tool BI mengenali pola bintang secara otomatis sehingga pengguna bisnis dapat memotong-motong data tanpa menulis SQL.
Keunggulan performa tersebut paling terasa pada pola akses analitik yang berulang: filter pada atribut dimensi, lalu agregasi measure fact — persis pola yang dijalankan dashboard setiap hari, sehingga keuntungan struktur menumpuk seiring pemakaian. Pola bintang juga ramah terhadap partisi waktu: karena seluruh baris fact membawa waktu_id, data lama dapat dipindahkan atau diarsipkan per rentang bulan tanpa menyentuh dimensi sama sekali.
Star schema bukan satu-satunya bentuk dimensional modeling — dimensi yang dipaksa tetap “lebar” kadang menimbulkan pengulangan data yang signifikan. Alternatif tersebut menormalisasi dimensi menjadi beberapa tabel dan dikenal sebagai Snowflake Schema, pembahasan chapter berikutnya.