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 :

sql
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:

sql
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:

sql
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:

text
Januari | Jakarta | 1500000 | 2
Januari | Bandung | 450000 | 1
Februari | Jakarta | 450000 | 1
Februari | Bandung | 300000 | 1
Maret | Jakarta | 1200000 | 1
Maret | Bandung | 300000 | 1

Mari kita telaah baris-baris kode di atas:

  1. Baris 1 (SELECT w.bulan, t.kota ...): atribut deskriptif langsung tersedia dari dimensi — tanpa subquery, tanpa join bertingkat.
  2. Baris 5-6 (dua JOIN): hanya dimensi yang relevan yang ikut — dim_pelanggan dan dim_produk tidak perlu digabung untuk pertanyaan ini.
  3. Baris 7 (GROUP BY w.bulan, t.kota): pemotongan analisis mengikuti kombinasi atribut dimensi.
  4. 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:

sql
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:

text
Budi | Reguler | 1800000
Siti | Reguler | 1650000
Dewi | Premium | 750000

Kelebihan 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.