Engine database: kapan pakai yang mana
Setiap aplikasi pada akhirnya menyimpan data, dan pertanyaan pertamanya hampir selalu sama: pakai database yang mana? Jawaban jujurnya bukan "yang tercepat" atau "yang paling populer" — tapi yang membuat pertanyaan paling sering Anda ajukan jadi satu pencarian yang murah.
Bayangkan sebuah gudang. Anda bisa menatanya dua cara. Cara pertama: masukkan semua yang dibutuhkan satu pelanggan ke dalam satu kotak berlabel — pesanan, alamat, pembayaran — lalu taruh kotaknya utuh di rak. Untuk melayani pelanggan itu, ambil satu kotak. Cara kedua: simpan rak terpisah untuk pesanan, pelanggan, dan produk, lalu telusuri benang di antaranya untuk merakit jawaban.
Hampir semua perdebatan "SQLⓘ vs NoSQLⓘ" sebenarnya soal itu: seberapa banyak data yang Anda kelompokkan jadi satu kotak, dan seberapa sering pertanyaan Anda harus menyeberang antar kotak. Mari telusuri enam keluarga engine — alur baca/tulis tiap engine, kapan memakainya, dan kasus produksi nyatanya.
Key-value — loket penitipan
Anda serahkan jaket, dapat nomor. Nanti tunjukkan nomornya, jaket persisnya kembali. Loketnya tak tahu dan tak peduli isi kantong jaket Anda — sangat cepat, mudah diskalakan, dan tak berguna kalau Anda harus bertanya "jaket mana yang biru?".
Kapan dipakai: cache, session, shopping cart, preferensi pengguna — apa pun yang diambil berdasarkan key. Netflix membangun EVCacheⓘ (cache in-memory di atas memcached) sebagai lapisan cache-nya: datanya ephemeralⓘ, punya TTLⓘ, dan bisa di-evict kapan saja. Amazon membangun Dynamoⓘ justru karena pola relational buruk untuk layanan high-availability seperti shopping cart dan session — yang hanya pernah diambil berdasarkan key — dan Dynamo sengaja menukar konsistensi kuat demi ketersediaan.
Document — map berlabel
Tiap pelanggan punya map manila berisi formulir terstruktur — nama, daftar pesanan, item bersarang. Anda buka map mana pun lewat labelnya, lalu baca atau ubah field tertentu tanpa membongkar semuanya.
Beda dari key-value, di sini tiap field bisa di-index dan di-query, dan Anda bisa memperbarui sebagian dokumen. Batasnya: skala horizontalⓘ menuntut Anda memilih shard keyⓘ di depan, dan modelnya tersiksa saat data Anda sebenarnya sangat terhubung.
Kapan dipakai: record berbentuk pohon yang mandiri — produk, halaman CMS, profil, satu pesanan.
Wide-column — lemari arsip baris jarang
Bayangkan satu spreadsheet raksasa; tiap baris dikunci oleh sesuatu yang selalu Anda cari — pengguna, channel, sensor — dan tiap baris bisa punya jutaan kolom, tapi cuma mengisi yang dibutuhkan. Anda tak pernah bertanya "tunjukkan semua baris yang kolom X-nya biru" ke seluruh lembar; Anda minta "kolom untuk baris ini, terurut". Itu harganya; imbalannya, lembar ini bisa dibelah ke ribuan mesin dan menyerap firehose tulisan tanpa berkedip.
Jalur tulisnya berbasis LSM-treeⓘ: tulisan masuk ke memtableⓘ (RAM, terurut) + commit log (append), langsung di-ack tanpa read-before-write, lalu di-flush ke SSTableⓘ immutable yang berkala di-compactⓘ. Itu sebabnya engine ini write-optimized. Penghapusan menulis tombstoneⓘ, jadi beban hapus-berat dan partisi panas perlahan memburuk.
Discord memindahkan penyimpanan pesannya tiga kali: MongoDB → Cassandra (2017) → ScyllaDB (2022).
Modelnya adalah desain query-driven yang jadi buku teks: pesan dipartisi berdasarkan channel_id + bucket
waktu, terurut lewat Snowflake IDⓘ, dengan replication factor 3 — partition key-nya adalah pola
aksesnya. Discord meninggalkan Cassandra karena partisi panas, jeda garbage collectionⓘ JVMⓘ, dan beban
compaction; ScyllaDB (tulisan ulang Cassandra dalam C++, tanpa garbage collector, arsitektur
shard-per-core) memangkas cluster dari 177 node jadi 72 node dan menurunkan p99 baca dari 40–125 ms
jadi 15 ms. Perhatikan: mereka tak mengganti model, hanya engine — masalah terbesarnya ada di runtime.
Kapan dipakai: firehose tulisan yang dikunci entitas + waktu (pesan, event, metrik, feed).
Columnar (OLAP) — kolom yang dipisah
Bayangkan semua kolom spreadsheet dicabik jadi daftar terpisah — semua "harga" di satu tempat, semua "negara" di tempat lain. Buruk untuk "ambil satu baris utuh", tapi luar biasa untuk "rata-rata harga 2 miliar penjualan, dikelompokkan per negara".
Tiap kolom disimpan dan dikompresi terpisah (nilai sejenis berdampingan menekan ukuran 10×+). Query menyentuh hanya kolom yang dirujuk, dalam loop vektor, dibagi lintas banyak node (MPPⓘ). Pas untuk SUM/GROUP BY atas miliaran baris; salah untuk "ambil satu baris utuh".
Kapan dipakai: scan + agregasi jutaan baris — dashboard, BI, analisis ad-hoc yang query-nya belum Anda ketahui di depan.
Graph — peta relasi
Alih-alih kotak mandiri, Anda menyimpan benang antar benda sebagai objek kelas satu. "Alice → teman → Bob → kerja-di → Acme" disimpan sebagai tautan nyata yang bisa ditelusuri satu langkah sekaligus. Pertanyaan seperti "teman-dari-teman yang bekerja di tempat teman saya bekerja" — yang membuat aggregate storeⓘ kewalahan — justru inti kekuatan graph.
Node dan relasi adalah warga kelas satu yang tersimpan fisik (index-free adjacencyⓘ), jadi menelusuriⓘ satu relasi adalah lompatan pointer, bukan join. Biayanya sebanding dengan subgraph yang disentuh, bukan ukuran total dataset — dasar teknis klaim bahwa saat jumlah "hop" bertambah, aggregate store melambat sementara graph tetap datar.
Relational — tabel bertaut dengan aturan
Tabel ternormalisasi yang Anda gabungkan dengan JOIN, dijaga aturan integritas, lalu di-commit secara transaksional. Fleksibel untuk relasi sedang, kuat soal kebenaran.
Kapan dipakai: join + agregasi lintas entitas yang harus tetap benar. Dan ini bukan pilihan kuno — Uber sengaja tidak membangun NoSQL. Docstore/Schemaless-nya dibangun di atas MySQL, membungkus tiap operasi dalam transaksi MySQL yang direplikasi lewat Raftⓘ demi jaminan ACIDⓘ. Mereka mengevaluasi Cassandra dan menolaknya — konsistensi eventualⓘ-nya menghambat produktivitas developer — lalu memilih desain CPⓘ (konsistensi di atas ketersediaan). Pelajarannya: "NoSQL di skala besar" bukan otomatis.
Time-series — titik di garis waktu
Monitor detak jantung, ticker saham, grafik CPU server: bentuk data yang sama — sebuah nilai berstempel waktu, di-append selamanya, dibaca ulang sebagai rentang dan rangkuman. Mayoritas append, berurut waktu, dan Anda nyaris tak pernah menulis ulang masa lalu.
Twist-nya: time-series bukan model penyimpanan ketujuh — ia spesialisasi dari keluarga di atas untuk satu workload ini. Di baliknya:
- TimescaleDB itu ekstensi PostgreSQL — relational plus kompresi columnar dan partisi-waktu otomatis.
- InfluxDB 3 menyimpan Apache Arrowⓘ / Parquetⓘ, jadi columnar; InfluxDB lama memakai engine TSMⓘ (LSM-tree), mirip wide-column.
- Prometheus punya store lokal gaya LSM sendiri, dan pola klasik partisi by
series + timepersis si firehose wide-column.
Jadi pakai TSDB khusus kalau Anda mau ergonomi waktu langsung jadi — kebijakan retensiⓘ, downsamplingⓘ, gap-fillingⓘ, fungsi time-bucketⓘ. Pakai wide-column atau columnar langsung kalau lebih suka memiliki modelnya dan sudah menjalankan salah satunya.
Butuh OLTP + OLAP? Jalankan keduanya
Kebanyakan perusahaan butuh dua-duanya, dan memaksa satu alat melakukan keduanya adalah kesalahan klasik. Polanya standar:
Lakukan
Hindari
Jangan menjalankan query analitik "GROUP BY lintas semuanya" langsung ke wide-column yang dikunci
channel_id. Itu memaksa scan seluruh cluster dan bisa menjatuhkan node yang sedang melayani trafik
live. Jangan pula memaksa columnar memperbarui baris satu per satu — ia membencinya.
Aturan satu kalimat: kalau yang bertanya manusia atau dashboard, arahkan ke columnar; kalau aplikasi Anda bertanya "ambil satu ini" pada skala besar, arahkan ke OLTP. Kalau dua-duanya benar, jalankan dua-duanya dan alirkan salah satu ke yang lain.
Sources