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:
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:
ORD-003 | 2025-02-05 | Budi | Mouse Wireless M10 | 1 | 150000Query 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:
EXPLAIN QUERY PLAN
SELECT * FROM detail_pesanan WHERE pesanan_id = 'ORD-003';Output yang Dihasilkan:
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:
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:
2025-01 | 3 | 1950000
2025-02 | 3 | 1800000Mari kita telaah baris-baris kode di atas:
- Baris 1 (
substr(p.tanggal, 1, 7) AS bulan): memotong tanggal ISO menjadi tahun-bulan (2025-01) sehingga menjadi kunci grup. - Baris 2-3 (
COUNT(*),SUM(d.qty * pr.harga)): dua agregasi — jumlah baris item dan pendapatan yang dihitung dari kuantitas kali harga satuan. - 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. - Baris 7-8 (
GROUP BY bulan,ORDER BY bulan): meringkas per bulan lalu mengurutkan hasilnya.
Rencana eksekusinya kini bercerita lain:
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:
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 BYSCAN 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 #
| Aspek | Database Operasional (OLTP) | Database Analitik (OLAP) |
|---|---|---|
| Pola beban | transaksi kecil, latensi milidetik | query besar agregasi, boleh detik-menit |
| Skema | dinormalisasi (3NF), minim redundansi | denormalisasi (star schema), minim join |
| Indexing | index terarah pada kolom pencarian | dioptimalkan untuk pemindaian dan agregasi |
| Concurrency | ribuan koneksi bersamaan, isolasi ketat | sedikit pengguna, query panjang |
| Operasi dominan | INSERT, UPDATE, SELECT satu baris | SELECT pemindaian + GROUP BY |
| Contoh database | PostgreSQL, MySQL | DuckDB, ClickHouse, BigQuery |
| Umur data | kondisi terkini | historis bertahun-tahun |
| Metrik sukses | transaksi per detik, latensi p99 | durasi 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.