Desain dimensi

Teknik desain dimensi, meliputi degenerate dimension dan slowly changing dimensions beserta penerapannya.

Daftar isi

Topik ini membahas dua teknik desain dimensi yang paling sering dipakai pada pemodelan Kimball, yaitu degenerate dimension untuk atribut transaksi dan slowly changing dimension untuk atribut yang berubah seiring waktu. Keduanya dijelaskan mulai dari masalah yang diselesaikannya. Pembahasan ditutup dengan demonstrasi slowly changing dimension tipe 2 yang dijalankan di DuckDB, sehingga mekanisme penutupan baris lama dan pembukaan baris baru terlihat pada keluaran aslinya.

Degenerate dimension: atribut transaksi tanpa tabel dimensi#

Degenerate dimension adalah atribut kejadian seperti nomor transaksi yang disimpan pada tabel fakta tanpa membentuk tabel dimensi, karena tidak ada atribut lain yang menyertainya. Nomor peminjaman pada perpustakaan dan nomor struk pada kasir toko alat tulis adalah contohnya. Nomor itu memang berperan seperti dimensi karena dapat dipakai memfilter dan mengelompokkan, tetapi isinya hanya satu kolom sehingga tabel dimensi terpisah justru membebani skema tanpa menambah informasi.

Degenerate dimension berguna untuk dua keperluan praktis. Pertama, penelusuran balik, yaitu menemukan kembali kejadian asli di sistem sumber dari nomornya. Kedua, penghitungan kejadian unik, misalnya berapa jumlah transaksi yang dilakukan seorang kasir, yang dijawab dengan penghitungan nilai unik kolom tersebut. Definisi Kimball menempatkannya sebagai kunci dimensi tanpa atribut yang menetap di fakta, sebagaimana tampak pada potongan skema berikut.

sql Contoh: nomor transaksi menetap pada tabel fakta
-- tidak-dijalankan
CREATE TABLE fakta_penjualan_kasir (
    no_transaksi VARCHAR NOT NULL,  -- degenerate dimension
    kunci_produk INTEGER NOT NULL,
    kunci_waktu  INTEGER NOT NULL,
    jumlah       INTEGER NOT NULL,
    total_harga  INTEGER NOT NULL
)

Potongan di atas menunjukkan bahwa no_transaksi diperlakukan seperti kunci dimensi, tetapi menetap di fakta dan tidak memiliki tabel pemiliknya. Pada fakta dengan grain satu baris per item struk, nomor yang sama berulang di beberapa baris, sehingga penghitungan transaksi menggunakan nilai uniknya dan bukan jumlah barisnya.

Slowly changing dimension: atribut dimensi yang berubah#

Slowly changing dimension (SCD) adalah teknik menangani atribut dimensi yang nilainya berubah seiring waktu, misalnya kota tempat tinggal pelanggan atau lokasi rak di perpustakaan. Persoalannya muncul karena tabel fakta terhubung ke dimensi lewat kunci. Apabila atribut dimensi ditimpa, seluruh angka historis tiba-tiba dibaca dengan konteks yang baru, dan analisis atas masa lalu menjadi menyesatkan.

Metode Kimball menetapkan beberapa tipe penanganan, dan tiga di antaranya dipakai paling sering. Tabel berikut membandingkan ketiganya.

TipePenangananRiwayatPenerapan yang cocok
Tipe 1nilai lama ditimpahilangperbaikan salah ketik yang tidak perlu dianalisis
Tipe 2baris baru dibuka, baris lama ditutuputuh per periodeperubahan yang perlu dianalisis, misalnya pindah kota
Tipe 3kolom tersendiri untuk nilai sebelumnyasatu langkahperubahan besar yang cukup diketahui nilai sebelumnya

Tipe 2 adalah pilihan paling lazim di warehouse karena mempertahankan riwayat tanpa memengaruhi kueri lain. Setiap perubahan menutup baris lama dengan mengisi batas akhir berlakunya, lalu membuka baris baru dengan kunci surogat yang berbeda. Pasangan kolom rentang berlaku, ditambah penanda baris aktif, menjaga setiap fakta tetap terhubung ke versi dimensi yang benar pada waktunya.

Demonstrasi SCD tipe 2#

Skrip berikut memuat versi awal dim_pelanggan berisi tiga pelanggan, lalu menghadapi kejadian perpindahan kota pada satu pelanggan. Baris lamanya ditutup, baris baru dibuka, dan isi tabel dicetak utuh. Di akhir, dua kueri versi menunjukkan atribut mana yang berlaku pada tanggal tertentu.

python scd-tipe2.py
"""Memperagakan slowly changing dimension tipe 2 pada dimensi pelanggan."""

import duckdb

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

con.execute("""
    CREATE TABLE dim_pelanggan (
        kunci_pelanggan INTEGER PRIMARY KEY,
        id_pelanggan    INTEGER NOT NULL,
        nama            VARCHAR NOT NULL,
        kota            VARCHAR NOT NULL,
        valid_from      DATE    NOT NULL,
        valid_to        DATE    NOT NULL,
        status          VARCHAR NOT NULL
    )
""")

# Muat versi awal tiga pelanggan
con.executemany("INSERT INTO dim_pelanggan VALUES (?, ?, ?, ?, ?, ?, ?)", [
    (101, 1, "Ali",   "Bandung",  "2026-01-01", "9999-12-31", "aktif"),
    (102, 2, "Budi",  "Bandung",  "2026-01-01", "9999-12-31", "aktif"),
    (103, 3, "Citra", "Semarang", "2026-01-01", "9999-12-31", "aktif"),
])

# Kejadian pada 2026-03-01: Citra pindah kota
# SCD tipe 2: tutup baris lama, lalu buka baris baru dengan kunci surogat sendiri
con.execute("""
    UPDATE dim_pelanggan
    SET valid_to = DATE '2026-02-28', status = 'riwayat'
    WHERE id_pelanggan = 3 AND status = 'aktif'
""")
con.execute("""
    INSERT INTO dim_pelanggan
    VALUES (104, 3, 'Citra', 'Yogyakarta', DATE '2026-03-01', DATE '9999-12-31', 'aktif')
""")

print("Isi dim_pelanggan setelah pembaruan SCD tipe 2:")
print("  kunci  id  nama   kota          dari        sampai      status")
rows = con.execute("SELECT * FROM dim_pelanggan ORDER BY kunci_pelanggan").fetchall()
for kunci, id_p, nama, kota, dari, sampai, status in rows:
    print(f"  {kunci:<6} {id_p:<3} {nama:<6} {kota:<13} {dari}  {sampai}  {status}")

# Kueri versi: atribut pelanggan yang berlaku pada sebuah tanggal
for tanggal in ("2026-02-15", "2026-03-05"):
    kota = con.execute("""
        SELECT kota FROM dim_pelanggan
        WHERE id_pelanggan = 3
          AND CAST(? AS DATE) BETWEEN valid_from AND valid_to
    """, [tanggal]).fetchone()[0]
    print(f"Kota Citra pada {tanggal}: {kota}")
text Keluaran
Isi dim_pelanggan setelah pembaruan SCD tipe 2:
  kunci  id  nama   kota          dari        sampai      status
  101    1   Ali    Bandung       2026-01-01  9999-12-31  aktif
  102    2   Budi   Bandung       2026-01-01  9999-12-31  aktif
  103    3   Citra  Semarang      2026-01-01  2026-02-28  riwayat
  104    3   Citra  Yogyakarta    2026-03-01  9999-12-31  aktif
Kota Citra pada 2026-02-15: Semarang
Kota Citra pada 2026-03-05: Yogyakarta

Keluarannya memperlihatkan empat baris untuk tiga pelanggan, dan selisih itulah inti tipe 2. Baris Citra versi Semarang berstatus riwayat dengan rentang berlaku yang tertutup, sedangkan versi Yogyakarta berstatus aktif dengan kunci surogat baru bernilai 104. Kueri versi lalu menjawab dengan tepat bahwa Citra berada di Semarang pada pertengahan Februari dan di Yogyakarta pada awal Maret. Baris fakta yang terjadi sebelum perpindahan tetap menunjuk kunci lama, sehingga angka historis tidak pernah berubah di belakang analisis.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul saat teknik dimensi ini dipraktikkan.

  1. Memakai tipe 1 tanpa menimbang kebutuhan analisis historis. Penyebabnya, penimpaan nilai terasa sederhana, padahal angka masa lalu ikut dibaca dengan konteks baru dan laporan yang sudah terbit tidak dapat direkonsiliasi. Perbaikannya, gunakan tipe 2 untuk atribut yang dianalisis sepanjang waktu dan sisakan tipe 1 untuk perbaikan kesalahan ketik.
  2. Menyisipkan baris baru tanpa menutup baris lama. Penyebabnya, dua versi aktif hidup bersamaan sehingga join dari fakta menggandakan baris dan total membengkak. Perbaikannya, tutup baris lama dan buka baris baru dalam satu transaksi, lalu uji dengan kueri yang menghitung baris aktif per kunci alami (natural key), yaitu kunci asli dari sistem sumber.
  3. Menjadikan kunci alami sebagai kunci join dari fakta. Penyebabnya, versi lama dan versi baru berbagi kunci yang sama sehingga riwayat tidak dapat dibedakan. Perbaikannya, hubungkan fakta ke kunci surogat yang berbeda untuk setiap versi, dan simpan kunci alami hanya sebagai atribut referensi.

Ringkasan#

  • Degenerate dimension menyimpan atribut transaksi seperti nomor struk langsung pada fakta karena atribut itu tidak memiliki kolom pembanding yang layak dimasukkan ke tabel dimensi.
  • Slowly changing dimension menangani atribut dimensi yang berubah, dengan tipe 1 menimpa, tipe 2 membuka baris baru, dan tipe 3 menyimpan satu nilai lampau.
  • SCD tipe 2 menutup baris lama, membuka baris baru dengan kunci surogat berbeda, dan menjaga setiap fakta terhubung ke versi yang benar pada waktunya.
  • Kesalahan paling merugikan adalah kehilangan riwayat secara tak disengaja dan baris aktif ganda, keduanya membuat angka analitik menyesatkan.

Referensi#