Star schema

Anatomi star schema, yaitu tabel fakta dan dimensi sebagai dasar pemodelan Kimball.

Daftar isi

Topik ini membedah anatomi star schema, yaitu bentuk pemodelan analitik yang menempatkan satu tabel fakta di tengah dan beberapa tabel dimensi di sekelilingnya. Pembahasannya mencakup peran tabel fakta, peran tabel dimensi, pengertian grain, dan kunci yang menghubungkan keduanya. Demonstrasi terakhir membangun star schema kecil di DuckDB untuk toko alat tulis, lalu menjalankan kueri analitik yang menyatukan kelima tabelnya sehingga strukturnya teruji pada keluaran nyata.

Tabel fakta dan tabel dimensi#

Star schema adalah pola pemodelan dari metode Kimball, yaitu kerangka pemodelan dimensi yang dirumuskan Ralph Kimball dan menjadi pendekatan warehouse yang paling banyak diajarkan. Dalam metode ini satu tabel fakta berada di tengah dan dikelilingi tabel dimensi yang terhubung melalui kunci, sehingga bentuk skemanya menyerupai bintang. Nama tabelnya pun mengikuti peran masing-masing dalam skema tersebut.

Tabel fakta (fact table) merekam kejadian bisnis satu baris per kejadian, misalnya satu transaksi penjualan, satu peminjaman buku, atau satu kunjungan klinik. Isinya berupa kunci-kunci yang menunjuk tabel dimensi ditambah measure, yaitu nilai numerik yang diukur dari kejadian tersebut, seperti jumlah unit dan total harga. Tabel fakta tumbuh paling cepat karena setiap kejadian baru menambah barisnya.

Tabel dimensi (dimension table) menyimpan konteks deskriptif yang menjawab pertanyaan siapa, apa, kapan, dan di mana atas setiap kejadian. Tabel produk memuat nama dan kategori, tabel pelanggan memuat nama dan kota, sedangkan tabel waktu memuat tanggal beserta atribut kalendernya seperti bulan. Jumlah barisnya jauh lebih kecil daripada fakta, tetapi kolomnya banyak karena di sinilah label dan filter analisis berasal.

Langkah pertama metode Kimball sebelum menulis satu pun tabel adalah mendeklarasikan grain, yaitu pernyataan tepat tentang apa yang diwakili satu baris fakta, misalnya satu baris per item struk per hari. Deklarasi ini menentukan ukuran yang boleh masuk ke fakta. Satu baris per item struk boleh menyimpan jumlah unit, sedangkan satu baris per struk tidak boleh menjumlahkan unit lintas produk karena ukurannya tidak lagi sebanding dengan barisnya.

Struktur star schema toko alat tulis#

Contoh yang dijalankan sepanjang topik ini berasal dari toko alat tulis dengan satu fakta bernama fakta_penjualan dan empat dimensi, yaitu dim_waktu, dim_produk, dim_pelanggan, serta dim_kasir. Diagram berikut menggambarkan susunannya beserta kolom utama setiap tabel.

Star schema: satu tabel fakta dikelilingi empat tabel dimensidim_waktukunci_waktu (PK)tanggal, bulandim_produkkunci_produk (PK)nama_produk, kategoridim_pelanggankunci_pelanggan (PK)nama_pelanggan, kotadim_kasirkunci_kasir (PK)nama_kasir, shiftfakta_penjualankunci_waktu, kunci_produk,kunci_pelanggan, kunci_kasirjumlah, total_harga
Struktur star schema toko alat tulis dengan satu tabel fakta dan empat tabel dimensi

Empat kunci dimensi pada fakta, yaitu kunci_waktu, kunci_produk, kunci_pelanggan, dan kunci_kasir, menunjuk kunci utama masing-masing dimensi. Kunci-kunci itu berupa kunci surogat (surrogate key), yaitu bilangan buatan yang hanya berlaku di dalam warehouse dan dipetakan ke kunci asli dari sistem sumber. Dua kolom terakhir pada fakta, jumlah dan total_harga, adalah ukuran yang diagregasi oleh kueri analitik.

Pola kueri pada star schema selalu seragam. Fakta menjadi tabel pusat, setiap dimensi di-join melalui kuncinya, filter dan label diambil dari kolom dimensi, sedangkan angka diambil dari ukuran. Karena pola join-nya selalu fakta ke dimensi, kueri yang kompleks pun mudah ditulis dan mudah dibaca mesin.

Membangun star schema kecil di DuckDB#

Skrip berikut membangun kelima tabel di DuckDB, memasukkan data toko alat tulis yang kecil, lalu menjalankan satu kueri analitik berupa total penjualan per bulan dan kategori produk. Setiap tabel dimensi diberi kunci utama, sedangkan kolom kunci pada fakta diberi kendala REFERENCES sehingga setiap baris fakta wajib menunjuk baris dimensi yang benar-benar ada. Data terbatas pada enam baris fakta agar hasilnya dapat dihitung ulang dengan mudah.

python bangun-star-schema.py
"""Membangun star schema kecil di DuckDB lalu menjalankan kueri analitiknya."""

import duckdb

con = duckdb.connect(":memory:")

con.execute("""
    CREATE TABLE dim_waktu (
        kunci_waktu INTEGER PRIMARY KEY,
        tanggal     DATE NOT NULL,
        bulan       VARCHAR NOT NULL
    )
""")
con.execute("""
    CREATE TABLE dim_produk (
        kunci_produk INTEGER PRIMARY KEY,
        nama_produk  VARCHAR NOT NULL,
        kategori     VARCHAR NOT NULL
    )
""")
con.execute("""
    CREATE TABLE dim_pelanggan (
        kunci_pelanggan INTEGER PRIMARY KEY,
        nama_pelanggan  VARCHAR NOT NULL,
        kota            VARCHAR NOT NULL
    )
""")
con.execute("""
    CREATE TABLE dim_kasir (
        kunci_kasir INTEGER PRIMARY KEY,
        nama_kasir  VARCHAR NOT NULL,
        shift       VARCHAR NOT NULL
    )
""")
con.execute("""
    CREATE TABLE fakta_penjualan (
        kunci_waktu    INTEGER NOT NULL REFERENCES dim_waktu(kunci_waktu),
        kunci_produk   INTEGER NOT NULL REFERENCES dim_produk(kunci_produk),
        kunci_pelanggan INTEGER NOT NULL REFERENCES dim_pelanggan(kunci_pelanggan),
        kunci_kasir    INTEGER NOT NULL REFERENCES dim_kasir(kunci_kasir),
        jumlah         INTEGER NOT NULL,
        total_harga    INTEGER NOT NULL
    )
""")

con.executemany("INSERT INTO dim_waktu VALUES (?, ?, ?)", [
    (1, "2026-02-02", "2026-02"),
    (2, "2026-02-03", "2026-02"),
    (3, "2026-02-04", "2026-02"),
])
con.executemany("INSERT INTO dim_produk VALUES (?, ?, ?)", [
    (1, "Pulpen Gel", "alat tulis"),
    (2, "Buku Tulis", "kertas"),
    (3, "Pensil 2B", "alat tulis"),
])
con.executemany("INSERT INTO dim_pelanggan VALUES (?, ?, ?)", [
    (1, "Ali", "Bandung"),
    (2, "Budi", "Bandung"),
    (3, "Citra", "Semarang"),
])
con.executemany("INSERT INTO dim_kasir VALUES (?, ?, ?)", [
    (1, "Dewi", "pagi"),
    (2, "Eka", "siang"),
])
con.executemany("INSERT INTO fakta_penjualan VALUES (?, ?, ?, ?, ?, ?)", [
    (1, 1, 1, 1, 2, 6000),
    (1, 2, 2, 1, 2, 14000),
    (2, 1, 3, 2, 3, 9000),
    (2, 3, 1, 2, 4, 8000),
    (3, 3, 2, 1, 2, 4000),
    (3, 2, 3, 2, 1, 7000),
])

n_fakta = con.execute("SELECT COUNT(*) FROM fakta_penjualan").fetchone()[0]
n_dim = con.execute("SELECT COUNT(*) FROM information_schema.tables WHERE table_name LIKE 'dim_%'").fetchone()[0]
print(f"Struktur: {n_dim} tabel dimensi, 1 tabel fakta ({n_fakta} baris)")

print("Kueri analitik: total penjualan per bulan dan kategori produk")
rows = con.execute("""
    SELECT w.bulan, p.kategori, SUM(f.jumlah) AS unit_terjual, SUM(f.total_harga) AS total
    FROM fakta_penjualan f
    JOIN dim_waktu w     ON w.kunci_waktu = f.kunci_waktu
    JOIN dim_produk p    ON p.kunci_produk = f.kunci_produk
    JOIN dim_pelanggan c ON c.kunci_pelanggan = f.kunci_pelanggan
    JOIN dim_kasir k     ON k.kunci_kasir = f.kunci_kasir
    GROUP BY w.bulan, p.kategori
    ORDER BY w.bulan, p.kategori
""").fetchall()
for bulan, kategori, unit, total in rows:
    print(f"  {bulan}  {kategori:<11} unit={unit:<3} total={total}")
text Keluaran
Struktur: 4 tabel dimensi, 1 tabel fakta (6 baris)
Kueri analitik: total penjualan per bulan dan kategori produk
  2026-02  alat tulis  unit=11  total=27000
  2026-02  kertas      unit=3   total=21000

Kuerinya menyentuh lima tabel sekaligus, tetapi strukturnya tetap sederhana karena seluruh join mengikuti pola yang sama dari fakta ke dimensi. Angka pada keluaran dapat dihitung ulang dari data mentahnya, misalnya kategori alat tulis menjual 11 unit senilai 27000 dari gabungan pulpen dan pensil. Inilah keuntungan bentuk bintang, yaitu pertanyaan bisnis seperti penjualan per kategori hampir langsung diterjemahkan menjadi SQL.

Keuntungan yang sama berlanjut pada skala nyata. Tabel fakta menyimpan jutaan baris sedangkan dimensinya jauh lebih kecil, sehingga banyak mesin analitik menyimpan dimensi di memori dan menyapu fakta sekali jalan. Prediktabilitas kinerja seperti inilah yang membuat star schema menjadi bentuk bawaan warehouse relasional.

Kesalahan umum#

Tiga kesalahan berikut sering muncul saat star schema pertama kali dirancang.

  1. Menyimpan teks deskriptif pada tabel fakta. Penyebabnya, nilai seperti nama produk dan kota pelanggan ikut diulang di setiap baris kejadian sehingga fakta gemuk dan rentan tidak konsisten. Perbaikannya, pindahkan seluruh atribut deskriptif ke tabel dimensi dan sisakan kunci beserta ukuran pada fakta.
  2. Mencampur beberapa grain dalam satu fakta. Penyebabnya, baris harian dan baris bulanan hidup berdampingan sehingga agregasi menghitung ulang angka yang sama. Perbaikannya, tetapkan satu grain per fakta dan buat fakta terpisah untuk grain yang berbeda.
  3. Membiarkan kunci dimensi berisi nilai ganda. Penyebabnya, join dari fakta menemukan lebih dari satu baris dimensi sehingga fakta tergandakan dan total membengkak. Perbaikannya, jadikan kunci utama setiap dimensi benar-benar unik dan uji dengan kueri penghitungan duplikat sebelum fakta dimuat.

Ringkasan#

  • Star schema menempatkan tabel fakta di tengah dan tabel dimensi di sekelilingnya, mengikuti metode Kimball.
  • Tabel fakta menyimpan kunci dimensi beserta ukuran numerik, sedangkan tabel dimensi menyimpan konteks deskriptif untuk label dan filter.
  • Grain dideklarasikan lebih dulu karena menentukan apa yang diwakili satu baris fakta dan ukuran apa yang sah dimasukkan.
  • Pola kuerinya seragam, yaitu fakta di-join ke dimensi lewat kunci surogat, sehingga pertanyaan bisnis mudah diterjemahkan menjadi SQL.

Referensi#