Di mata banyak orang, kata “database” merujuk pada satu kategori tunggal: tempat menyimpan data. Kenyataannya, database yang menjalankan aplikasi kasir dan database yang menjawab laporan manajemen dioptimalkan untuk dua pekerjaan yang bertolak belakang. Database operasional (OLTP) mengejar transaksi kecil yang selesai dalam milidetik, sedangkan database analitik (OLAP) mengejar query besar yang memindai jutaan baris. Pada chapter ini kita akan melihat perbedaan keduanya secara konkret: query kontras pada data toko online yang sama, rencana eksekusinya, lalu perbandingan menyeluruh mulai dari skema hingga concurrency.

Pola Beban: Transaksi Kecil vs Query Besar #

Pola beban (workload) adalah pembeda paling mendasar. Aplikasi pesanan toko online kita menjalankan ribuan transaksi per jam — setiap transaksi hanya menyentuh beberapa baris: satu baris pesanan, dua-tiga baris detail_pesanan, satu baris stok. Sebaliknya, dashboard manajemen menjalankan belasan query per hari, tetapi setiap query harus membaca seluruh detail_pesanan berisi jutaan baris untuk menghitung pendapatan per bulan. Satu pilihan desain tidak mungkin mengoptimalkan keduanya sekaligus, sehingga dua jenis database tumbuh menjadi dua disiplin berbeda.

Query OLTP: Cepat dan Spesifik #

Database operasional toko kita menyimpan data dalam empat tabel dinormalisasi: pelanggan, produk, pesanan (header), dan detail_pesanan (baris item), dengan index idx_detail_pesanan pada kolom pesanan_id. Query OLTP khas mengambil satu pesanan secara utuh — header pelanggan beserta seluruh itemnya:

sql
SELECT p.pesanan_id, p.tanggal, pl.nama, pr.nama, d.qty, pr.harga
FROM pesanan p
JOIN pelanggan pl ON pl.pelanggan_id = p.pelanggan_id
JOIN detail_pesanan d ON d.pesanan_id = p.pesanan_id
JOIN produk pr ON pr.produk_id = d.produk_id
WHERE p.pesanan_id = 'ORD-003';

Output yang Dihasilkan:

text
ORD-003 | 2025-02-05 | Budi | Mouse Wireless M10 | 1 | 150000

Query di atas menyentuh satu pesanan milik Budi dan selesai hampir seketika. Rencana eksekusi untuk pencarian baris detail-nya memperlihatkan ciri khas OLTP — database tidak memindai tabel, melainkan melompat langsung lewat index:

sql
EXPLAIN QUERY PLAN
SELECT * FROM detail_pesanan WHERE pesanan_id = 'ORD-003';

Output yang Dihasilkan:

text
SEARCH detail_pesanan USING INDEX idx_detail_pesanan (pesanan_id=?)

Kata SEARCH ... USING INDEX berarti hanya beberapa entri index yang dibaca, bukan seluruh tabel. Inilah profil yang diinginkan setiap transaksi OLTP.

Query OLAP: Pindai dan Agregasi #

Query analitik mengajukan pertanyaan yang berbeda pada data yang sama: berapa pendapatan toko per bulan? Semua baris harus dibaca, dijoin, lalu diagregasi:

sql
SELECT substr(p.tanggal, 1, 7) AS bulan,
       COUNT(*) AS jumlah_baris,
       SUM(d.qty * pr.harga) AS pendapatan
FROM detail_pesanan d
JOIN pesanan p ON p.pesanan_id = d.pesanan_id
JOIN produk pr ON pr.produk_id = d.produk_id
GROUP BY bulan
ORDER BY bulan;

Output yang Dihasilkan:

text
2025-01 | 3 | 1950000
2025-02 | 3 | 1800000

Mari kita telaah baris-baris kode di atas:

  1. Baris 1 (substr(p.tanggal, 1, 7) AS bulan): memotong tanggal ISO menjadi tahun-bulan (2025-01) sehingga menjadi kunci grup.
  2. Baris 2-3 (COUNT(*), SUM(d.qty * pr.harga)): dua agregasi — jumlah baris item dan pendapatan yang dihitung dari kuantitas kali harga satuan.
  3. Baris 5-6 (dua JOIN): merangkai tiga tabel dinormalisasi (detail_pesanan, pesanan, produk) menjadi satu dataset analitik; inilah biaya struktur 3NF yang harus dibayar setiap query OLAP.
  4. Baris 7-8 (GROUP BY bulan, ORDER BY bulan): meringkas per bulan lalu mengurutkan hasilnya.

Rencana eksekusinya kini bercerita lain:

sql
EXPLAIN QUERY PLAN
SELECT substr(p.tanggal, 1, 7), SUM(d.qty * pr.harga)
FROM detail_pesanan d
JOIN pesanan p ON p.pesanan_id = d.pesanan_id
JOIN produk pr ON pr.produk_id = d.produk_id
GROUP BY substr(p.tanggal, 1, 7);

Output yang Dihasilkan:

text
SCAN d
SEARCH p USING INDEX sqlite_autoindex_pesanan_1 (pesanan_id=?)
SEARCH pr USING INTEGER PRIMARY KEY (rowid=?)
USE TEMP B-TREE FOR GROUP BY

SCAN d berarti seluruh tabel detail_pesanan dibaca dari awal hingga akhir — perilaku yang benar untuk OLAP karena memang semua baris diperlukan. USE TEMP B-TREE FOR GROUP BY menunjukkan database membangun struktur sementara untuk agregasi. Pada tabel berisi jutaan baris, pemindaian semacam inilah yang membuat database analitik seperti DuckDB memakai format penyimpanan kolom agar pemindaian jauh lebih cepat.

Perbandingan Menyeluruh #

AspekDatabase Operasional (OLTP)Database Analitik (OLAP)
Pola bebantransaksi kecil, latensi milidetikquery besar agregasi, boleh detik-menit
Skemadinormalisasi (3NF), minim redundansidenormalisasi (star schema), minim join
Indexingindex terarah pada kolom pencariandioptimalkan untuk pemindaian dan agregasi
Concurrencyribuan koneksi bersamaan, isolasi ketatsedikit pengguna, query panjang
Operasi dominanINSERT, UPDATE, SELECT satu barisSELECT pemindaian + GROUP BY
Contoh databasePostgreSQL, MySQLDuckDB, ClickHouse, BigQuery
Umur datakondisi terkinihistoris bertahun-tahun
Metrik suksestransaksi per detik, latensi p99durasi query, throughput pemindaian

Skema dan indexing pada tabel di atas saling terkait. OLTP menormalkan data agar setiap UPDATE menyentuh satu baris saja, dan memasang index secukupnya karena setiap index tambahan memperlambat penulisan. OLAP justru menerima redundansi demi join yang sedikit, lalu membangun index dan format penyimpanan yang mempercepat pemindaian kolom yang sering diagregasi.

Concurrency melengkapi pembeda tersebut. Database operasional melayani ribuan koneksi yang berebut baris, sehingga isolasi transaksi dan lock baris harus ketat. Database analitik hanya melayani sedikit pengguna dengan query panjang; tanpa beban tulis bersamaan, engine analitik bebas memakai format penyimpanan kolom yang mempercepat pemindaian besar. Konsekuensinya, memakai satu database untuk dua peran sekaligus membuat transaksi dan analitik saling mengganggu.

Dua profil database tersebut kini terlihat jelas, dan tugas kita sebagai data engineer adalah memindahkan data dari profil pertama ke profil kedua dengan benar. Pekerjaan pemindahan inilah yang dibingkai Ralph Kimball dalam buku The Data Warehouse Toolkit sebagai dimensional modeling — kerangka desain yang akan kita pelajari pada chapter Dimensional Modeling.