Mendalami arsitektur data warehouse cloud modern: perbandingan Snowflake, BigQuery, dan Redshift, konsep pemisahan storage & compute, partitioning dan clustering yang benar, serta strategi cost management dan praktik optimasi query di warehouse

Di episode 8 kalian telah mengorkestrasi pipeline batch dengan Airflow. Tapi ke mana data itu dimuat? Di episode 6 kita memakai PostgreSQL sebagai "warehouse" — itu cukup untuk belajar, tapi warehouse produksi adalah kelas yang berbeda. Episode ini membuka pintu ke data warehouse cloud: mengapa ia dibuat terpisah, bagaimana Snowflake/BigQuery/Redshift bekerja, dan bagaimana kalian membuat query serta tagihan tetap sehat.
Mengapa topik ini penting? Karena warehouse adalah jantung serving layer dari seluruh arsitektur data. Keputusan di sini — partitioning, clustering, pemilihan teknologi — berdampak langsung pada performa dashboard dan biaya bulanan. Data engineer yang menguasai warehouse adalah aset langka.
Warehouse modern (Snowflake, BigQuery) dibangun di atas satu ide revolusioner: memisahkan storage dari compute.
Dampaknya luar biasa: storage bisa berisi terabyte dengan biaya rendah, sementara compute bisa "tidur" saat tidak ada pekerjaan. Inilah yang membuat ELT dengan data mentah di warehouse menjadi praktis (episode 6).
| Aspek | Snowflake | BigQuery | Redshift |
|---|---|---|---|
| Compute | Virtual warehouse (multi-cluster) | Slots berbagi, serverless | Cluster provisioned |
| Storage | Pemisahan penuh | Pemisahan penuh | Terhubung dengan compute |
| Pricing | Compute + storage terpisah | Bayar per query/slot | Bayar per jam cluster |
| Serverless | Semi (auto-suspend) | Ya, penuh | Tidak (redshift serverless ada) |
| Kekuatan | Multi-cloud, isolasi workload | Integrasi GCP, skala raksasa | Ekosistem AWS, familiar |
Ketiganya sama-sama kolumnar dan memakai SQL. Pilihan biasanya ditentukan oleh ekosistem cloud yang sudah dipakai organisasi — bukan murni teknis.
Di dunia warehouse kolumnar, dua mekanisme menentukan kecepatan query: partitioning dan clustering/sorting. Keduanya bekerja dengan prinsip yang sama: hindari memindai data yang tidak dibutuhkan.
Membagi tabel secara fisik berdasarkan kolom (biasanya tanggal), sehingga query yang memfilter satu partisi hanya membaca sebagian kecil data.
CREATE TABLE analytics.orders
PARTITION BY DATE(created_at)
AS SELECT * FROM staging.orders;CREATE TABLE analytics.orders
CLUSTER BY (created_at);Partisi harian adalah default yang tepat untuk sebagian besar tabel fakta. Tapi hati-hati: terlalu banyak partisi kecil (misalnya per jam untuk tabel kecil) justru memperlambat query karena overhead metadata.
Mengurutkan baris dalam partisi berdasarkan kolom tertentu, sehingga filter pada kolom itu bisa melompati blok yang tidak relevan:
CREATE TABLE analytics.orders
PARTITION BY DATE(created_at)
CLUSTER BY customer_id
AS SELECT * FROM staging.orders;Aturan praktis: partisi untuk kolom waktu (paling sering difilter), cluster untuk kolom kardinalitas sedang yang sering difilter bersamaan (customer_id, store_id, region).
Note
Partisi berbeda dengan partisi di PostgreSQL: warehouse kolumnar memotong file fisik, bukan hanya index. Filter tanggal yang tidak memakai partisi di BigQuery bisa menagih biaya scan penuh — salah satu penyebab tagihan membengkak.
Biaya warehouse bukan misteri — ia mengikuti data yang di-scan dan compute yang dipakai. Empat prinsip pengendalian biaya:
SELECT hanya kolom yang dibutuhkan, bukan SELECT *.SELECT * FROM table oleh analyst bisa menghabiskan kuota harian. Sediakan data mart yang sudah teragregasi.-- Dry run menghitung bytes yang akan di-scan tanpa menjalankan query
bq query --dry_run --use_legacy_sql=false "SELECT * FROM analytics.orders"Perintah di atas adalah cara paling cepat tahu apakah query kalian boros — sebelum benar-benar menjalankannya. Topik optimasi biaya menyeluruh kita bahas di episode 22.
Mari optimasi satu query dari "boros" menjadi "efisien":
SELECT
customer_id,
DATE(created_at) AS order_date,
SUM(amount) AS total
FROM analytics.orders
WHERE amount > 100
GROUP BY customer_id, DATE(created_at);Masalahnya: filter amount > 100 tidak memanfaatkan partisi maupun clustering, sehingga database memindai semua partisi. Versi optimasi:
SELECT
customer_id,
DATE(created_at) AS order_date,
SUM(amount) AS total
FROM analytics.orders
WHERE created_at >= TIMESTAMP('2026-08-01')
AND created_at < TIMESTAMP('2026-09-01')
AND customer_id IN (101, 202, 303)
GROUP BY customer_id, DATE(created_at);Perbedaan prinsipnya: pindahkan filter ke kolom partisi/cluster. Alih-alih memindai 30 hari penuh (atau seluruh tabel), query kini hanya membaca partisi Agustus dan blok-blok customer yang relevan — scan berkurang drastis, biaya ikut turun.
SELECT * di warehouse. Setiap kolom yang di-scan berbayar. Pilih kolom secara eksplisit.
Partisi tanpa kebutuhan filter. Mempartisi kolom yang tidak pernah difilter hanya menambah overhead metadata.
Mengabaikan perbedaan antara warehouse. Sintaks partitioning di BigQuery vs Snowflake vs Redshift berbeda — jangan copy-paste antar platform tanpa adaptasi.
Tidak membaca query plan/biaya. Warehouse menyediakan tools (BigQuery dry run, Snowflake query profile) untuk melihat boros/tidaknya query. Biasakan memakainya.
Di episode 9 ini kalian telah menguasai warehouse cloud:
SELECT eksplisit, partisi tepat, suspend idle compute.Di episode 10 selanjutnya kita membangun untuk volume yang lebih besar: data lake & lakehouse (Spark/Databricks) — format file Parquet/Avro, tabel Iceberg & Delta Lake, serta batch processing dengan PySpark. Sampai jumpa di episode 10!