Fact table yang dibangun di Chapter Grain dalam Data Model mencatat kejadian: satu baris untuk satu transaksi penjualan. Namun banyak pertanyaan analitik menyasar keadaan, bukan kejadian — berapa sisa stok produk pada 3 Januari, berapa saldo poin pelanggan akhir bulan, atau sudah sampai tahap mana sebuah pesanan diproses. Pertanyaan seperti tersebut tidak bisa dijawab dari daftar transaksi tanpa menghitung ulang seluruh riwayat setiap kali. Snapshot table menyimpan keadaan pada titik waktu tertentu sehingga jawabannya tinggal dibaca.

Periodic Snapshot vs Accumulating Snapshot #

Periodic snapshot menangkap keadaan pada jadwal tetap: setiap malam, saldo stok seluruh produk ditulis satu baris per produk. Accumulating snapshot menyimpan perjalanan satu entitas dalam satu baris yang diperbarui setiap kali milestone tercapai: pesanan yang baru dibuat, lalu dibayar, lalu dikirim, tercatat sebagai satu baris yang kolom-kolom waktunya terisi bertahap.

AspekPeriodic SnapshotAccumulating Snapshot
Isi satu bariskeadaan pada satu titik waktuperjalanan satu entitas dari awal sampai akhir
Waktu tulisjadwal teratur (harian, mingguan)setiap milestone terjadi
Pola tulissisip baris baru per periodeperbarui baris yang sama berulang
Pertanyaan yang dijawabberapa stok pada tanggal Hberapa lama pesanan menunggu pengiriman
Contohsaldo rekening, stok gudangstatus pesanan, proses klaim

Full vs Incremental Snapshot #

Snapshot full menyalin ulang seluruh keadaan setiap periode. Dengan 5.000 produk aktif, tabel stok harian bertambah 5.000 baris per hari terlepas dari berapa produk yang benar-benar berubah. Pendekatan tersebut sederhana dan mudah dibangun ulang, tetapi biaya penyimpanan tumbuh cepat untuk dimensi besar.

Snapshot incremental hanya menulis keadaan yang berubah sejak periode terakhir, biasanya lewat pola upsert pada kunci (tanggal, kode_produk). Bila hanya 300 dari 5.000 produk berubah hari itu, hanya 300 baris yang ditulis. Imbalannya, pipeline harus mampu mendeteksi perubahan — misalnya memanfaatkan kolom updated_at di sumber atau pola CDC — dan kegagalan di tengah proses harus aman diulang, tema yang sudah dibahas pada Course Data Pipeline Engineering.

Pilihan strategi juga menentukan apa yang bisa dibuktikan. Snapshot full mencatat keadaan lengkap setiap periode — produk yang tidak berubah pun tetap muncul, sehingga tabel bisa dijadikan bukti audit keadaan pada tanggal tertentu. Snapshot incremental hanya menyimpan jejak perubahan, sehingga keadaan tanggal tertentu harus direkonstruksi dari baris perubahan terakhir sebelum tanggal tersebut.

Contoh: Snapshot Stok Harian #

Kita bangun periodic snapshot stok toko online selama tiga hari. Primary key gabungan (tanggal, kode_produk) membuat snapshot per tanggal tidak pernah berisi duplikat — menjalankan ulang snapshot tanggal yang sama dua kali tetap menghasilkan keadaan yang tunggal.

python
import sqlite3

koneksi = sqlite3.connect(":memory:")
cur = koneksi.cursor()

# --- Periodic snapshot: stok per produk diambil setiap malam ---
cur.execute("""
CREATE TABLE snapshot_stok (
    tanggal     TEXT NOT NULL,
    kode_produk TEXT NOT NULL,
    stok        INTEGER NOT NULL,
    PRIMARY KEY (tanggal, kode_produk)
)
""")

stok_harian = {
    "2026-01-01": {"P-100": 50, "P-200": 10},
    "2026-01-02": {"P-100": 45, "P-200": 8},
    "2026-01-03": {"P-100": 40, "P-200": 0},
}
for tanggal, produk in stok_harian.items():
    for kode, jumlah in produk.items():
        cur.execute(
            "INSERT INTO snapshot_stok VALUES (?, ?, ?)", (tanggal, kode, jumlah)
        )

print("Agregat dari snapshot stok tiga hari:")
for baris in cur.execute(
    """SELECT kode_produk,
              COUNT(*)            AS jumlah_hari,
              ROUND(AVG(stok), 1) AS rata_stok,
              MIN(stok)           AS stok_min
       FROM snapshot_stok
       GROUP BY kode_produk"""
):
    print(" ", baris)

Output yang Dihasilkan:

text
Agregat dari snapshot stok tiga hari:
  ('P-100', 3, 45.0, 40)
  ('P-200', 3, 6.0, 0)

Mari kita telaah baris-baris kode di atas:

  1. Baris 7-14 (CREATE TABLE snapshot_stok): primary key gabungan tanggal dan produk menegaskan grain snapshot — satu baris berarti keadaan satu produk pada satu hari; kunci ini sekaligus menjadi pengaman idempotent saat snapshot dijalankan ulang.
  2. Baris 16-25 (pemuatan tiga hari): loop menulis keadaan setiap produk setiap hari; nilai P-200 yang mencapai 0 pada hari ketiga tetap direkam karena produk tanpa transaksi pun ikut di-snapshot.
  3. Baris 28-36 (agregat): karena snapshot tersimpan per hari, rata-rata dan minimum stok dihitung dengan agregat biasa tanpa membuka ulang transaksi penjualan — inilah manfaat utama periodic snapshot.

Accumulating Snapshot: Status Pesanan #

Untuk status pesanan, accumulating snapshot memakai satu baris per pesanan dengan kolom waktu per milestone. Baris yang sama diperbarui ketika pesanan maju tahap, sehingga tabel selalu memperlihatkan posisi terkini setiap pesanan.

python
# --- Accumulating snapshot: satu baris per pesanan, diperbarui mengikuti siklus ---
cur.execute("""
CREATE TABLE snapshot_pesanan (
    id_pesanan   TEXT PRIMARY KEY,
    status       TEXT NOT NULL,
    dibuat_pada  TEXT,
    dibayar_pada TEXT,
    dikirim_pada TEXT
)
""")

cur.execute(
    "INSERT INTO snapshot_pesanan VALUES ('ORD-1', 'dibuat', '2026-01-02 08:00', NULL, NULL)"
)
cur.execute(
    """UPDATE snapshot_pesanan
       SET status = 'dibayar', dibayar_pada = '2026-01-02 08:05'
       WHERE id_pesanan = 'ORD-1'"""
)
cur.execute(
    """UPDATE snapshot_pesanan
       SET status = 'dikirim', dikirim_pada = '2026-01-03 09:00'
       WHERE id_pesanan = 'ORD-1'"""
)

print()
print("Accumulating snapshot ORD-1 (satu baris, tiga pembaruan):")
print(" ", cur.execute("SELECT * FROM snapshot_pesanan").fetchall())

print()
print("Pesanan dengan jeda bayar ke kirim lebih dari sehari:")
for baris in cur.execute(
    """SELECT id_pesanan, dibayar_pada, dikirim_pada
       FROM snapshot_pesanan
       WHERE dikirim_pada IS NOT NULL
         AND julianday(dikirim_pada) - julianday(dibayar_pada) > 1"""
):
    print(" ", baris)

Output yang Dihasilkan:

text
Accumulating snapshot ORD-1 (satu baris, tiga pembaruan):
  [('ORD-1', 'dikirim', '2026-01-02 08:00', '2026-01-02 08:05', '2026-01-03 09:00')]

Pesanan dengan jeda bayar ke kirim lebih dari sehari:
  ('ORD-1', '2026-01-02 08:05', '2026-01-03 09:00')

Tiga pernyataan SQL menyentuh baris ORD-1 — insert saat dibuat, update saat dibayar, update lagi saat dikirim — dan hasil akhirnya tetap satu baris dengan seluruh milestone terisi. Query terakhir menghitung durasi antar-milestone langsung dari kolom yang ada, memakai fungsi julianday yang mengubah timestamp menjadi jumlah hari (dokumentasinya di dokumentasi SQLite ); pola pembaruan berkala seperti ini juga lazim diotomatisasi lewat model incremental dbt di docs.getdbt.com .

Warehouse inti kini punya fakta, dimensi, dan snapshot. Langkah berikutnya adalah memotongnya menjadi porsi yang siap saji per departemen — pekerjaan Chapter Data Marts.