BigQuery / DuckDB — Data Engineering

Columnar Databases: BigQuery & DuckDB Database columnar menyimpan data per kolom, bukan per baris. Ini membuatnya sangat cepat untuk query analitik yang hanya…

BigQuery dan DuckDB sama-sama mesin SQL analitik yang menyimpan data per kolom, tapi tinggal di tempat yang berlawanan. BigQuery adalah warehouse di cloud Google: gak ada server yang kamu urus, dan kamu bayar per byte data yang dibaca query. DuckDB adalah library yang jalan di dalam program kamu sendiri, di laptop, dan bisa langsung membaca file Parquet dan CSV. Bayangin cucian. BigQuery itu laundry kiloan: tinggal serahkan, mesinnya bukan urusanmu, bayarnya per kilo. DuckDB itu mesin cuci di rumah: gratis tiap kali pakai, tapi muatannya sebatas mesinmu.

🧪 Tebakan cepat: analis menjalankan SELECT * FROM penjualan LIMIT 10 di BigQuery untuk mengintip isi tabel. Tabelnya 1 miliar baris. Yang ditagih 10 baris atau seluruh tabel? Tebak dulu, jawabannya ada di bagian "BigQuery: bayar per byte yang dibaca".

Dua mesin columnar, dua tempat

DuckDB BigQuery
Jalan di mana di dalam proses Python, Node, atau CLI kamu (in-process) di server Google (serverless: servernya ada, tapi bukan urusanmu)
Mulai pakai pip install duckdb akun Google Cloud, project, dataset
Data file Parquet, CSV, JSON di disk atau di S3, tabel DuckDB sendiri tabel BigQuery (storage-nya ikut dibayar)
Biaya gratis, open source per byte yang dibaca query, plus storage
Skala sebatas satu mesin: sampai ratusan GB masih nyaman terabyte sampai petabyte, banyak orang sekaligus

Keunggulan utama DuckDB dibanding warehouse cloud: dia jalan lokal tanpa server, jadi cocok untuk eksplorasi data di laptop developer, untuk test pipeline, dan untuk script yang mengolah file. Semua output DuckDB di pelajaran ini dari DuckDB 1.5.6 (rilis terbaru di PyPI per 11 Oktober 2026).

DuckDB: pertanyaan pemilik di laptop

Datanya order_lines.csv dan books.csv dari pelajaran pandas. Script ini membuat file penjualan.parquet (18 baris bersih, tanpa kolom minggu), lalu menjawab pertanyaan pemilik langsung dari file itu:

import duckdb

print(duckdb.__version__)

# 1. Extract jadi file Parquet: 18 baris bersih, tanpa server
duckdb.sql("""
    COPY (
        SELECT DISTINCT r.order_id, r.book_id,
               CAST(r.created_at AS DATE) AS tanggal,
               COALESCE(r.city, 'Tidak diketahui') AS kota,
               r.title AS judul,
               r.qty,
               b.catalog_price AS harga
        FROM 'order_lines.csv' r
        JOIN 'books.csv' b USING (book_id)
    ) TO 'penjualan.parquet' (FORMAT parquet)
""")

# 2. Pertanyaan pemilik, langsung dari file Parquet
duckdb.sql("""
    SELECT date_trunc('week', tanggal)::DATE AS minggu, kota, judul, SUM(qty) AS terjual
    FROM 'penjualan.parquet'
    WHERE tanggal BETWEEN '2026-09-28' AND '2026-10-11'
    GROUP BY minggu, kota, judul
    QUALIFY RANK() OVER (PARTITION BY minggu, kota ORDER BY terjual DESC) = 1
    ORDER BY minggu, kota, judul
""").show()
1.5.6
┌────────────┬─────────────────┬──────────────────────┬─────────┐
│   minggu   │      kota       │        judul         │ terjual │
│    date    │     varchar     │       varchar        │ int128  │
├────────────┼─────────────────┼──────────────────────┼─────────┤
│ 2026-09-28 │ Bandung         │ Bumi Manusia         │       2 │
│ 2026-09-28 │ Jakarta         │ Laskar Pelangi       │       3 │
│ 2026-09-28 │ Surabaya        │ Cantik Itu Luka      │       2 │
│ 2026-09-28 │ Tidak diketahui │ Laskar Pelangi       │       1 │
│ 2026-10-05 │ Bandung         │ Ronggeng Dukuh Paruk │       2 │
│ 2026-10-05 │ Jakarta         │ Cantik Itu Luka      │       2 │
│ 2026-10-05 │ Surabaya        │ Laskar Pelangi       │       1 │
│ 2026-10-05 │ Surabaya        │ Ronggeng Dukuh Paruk │       1 │
│ 2026-10-05 │ Tidak diketahui │ Bumi Manusia         │       1 │
└────────────┴─────────────────┴──────────────────────┴─────────┘

BigQuery: bayar per byte yang dibaca

Di BigQuery kamu gak menyewa server. Tiap query dihitung dari jumlah byte di kolom yang dibaca, dengan harga on-demand US$6,25 per TiB (1 TiB = 1.024 GiB), dan 1 TiB pertama tiap bulan gratis. Storage 10 GiB pertama tiap bulan juga gratis. Angka ini dari halaman resmi cloud.google.com/bigquery/pricing per 11 Oktober 2026, untuk region us-central1 (Iowa); region lain bisa beda harganya. Aturan lain di halaman yang sama:

Ukuran tiap nilai juga sudah ditentukan: INT64 dan DATE 8 byte, STRING 2 byte ditambah panjang teksnya. Untuk tabel penjualan dari pelajaran sebelumnya:

Kolom Tipe Byte untuk 18 baris
order_id, book_id, qty, harga INT64 144 per kolom
tanggal, minggu DATE 144 per kolom
kota STRING 182
judul STRING 306

SELECT * membaca 1.352 byte, pertanyaan pemilik (tanggal, kota, judul, qty) 776 byte; dua-duanya ditagih minimal 10 MB, dan gratis selama masih di bawah 1 TiB sebulan. Bedanya baru terasa kalau tabelnya besar. Misalnya marketplace buku dengan 1 miliar baris penjualan selama 3 tahun (1.096 hari), dan dashboard yang menjalankan query tiap 5 menit (8.640 query sebulan):

Query Dibaca per query Biaya per query Sebulan, setelah 1 TiB gratis
SELECT * 69,95 GiB US$0,43 US$3.682,68
4 kolom yang perlu 40,15 GiB US$0,25 US$2.111,06
4 kolom, 2 minggu terakhir, tabel dipartisi 0,51 GiB US$0,0031 US$20,84

Partisi dan cluster: memotong byte

CREATE TABLE `toko-buku.gudang.penjualan` (
  order_id INT64, book_id INT64,
  tanggal DATE, minggu DATE,
  kota STRING, judul STRING,
  qty INT64, harga INT64
)
PARTITION BY tanggal
CLUSTER BY kota;

Satu pertanyaan, tiga dialek

SQL di tiap mesin mirip, tapi gak sama. Pertanyaan pemilik di tiga tempat:

SQLite (Playground dan Lab) DuckDB BigQuery
Senin awal minggu date(tanggal, 'weekday 0', '-6 days') date_trunc('week', tanggal)::DATE DATE_TRUNC(tanggal, WEEK(MONDAY))
Menyaring hasil RANK() CTE, lalu WHERE di query luar QUALIFY QUALIFY
Nama tabel penjualan 'penjualan.parquet' `toko-buku.gudang.penjualan`

Di BigQuery, urutan argumennya terbalik dari DuckDB, dan WEEK tanpa (MONDAY) mulai hari Minggu. date(...) di SQLite adalah singkatan strftime('%Y-%m-%d', ...). Versi BigQuery-nya (gak dijalankan di pelajaran ini, karena butuh akun Google Cloud):

SELECT DATE_TRUNC(tanggal, WEEK(MONDAY)) AS minggu, kota, judul, SUM(qty) AS terjual
FROM `toko-buku.gudang.penjualan`
WHERE tanggal BETWEEN '2026-09-28' AND '2026-10-11'
GROUP BY minggu, kota, judul
QUALIFY RANK() OVER (PARTITION BY DATE_TRUNC(tanggal, WEEK(MONDAY)), kota ORDER BY SUM(qty) DESC) = 1
ORDER BY minggu, kota, judul;

Versi SQLite-nya ada di Lab, dan jawabannya sama: 9 baris.

Kapan pilih yang mana

⚠️ Jebakan yang sering ketemu

TL;DR: BigQuery dan DuckDB sama-sama columnar. DuckDB jalan di dalam program kamu tanpa server (pip install duckdb, versi 1.5.6), membaca Parquet dan CSV langsung (FROM 'penjualan.parquet'), gratis, dan cocok untuk eksplorasi di laptop. BigQuery adalah warehouse serverless di cloud: bayar US$6,25 per TiB yang dibaca (us-central1, per Oktober 2026), 1 TiB pertama tiap bulan gratis, minimal 10 MB per tabel, dan LIMIT gak mengurangi tagihan. Hemat byte dengan menyebut kolom yang perlu dan menyaring tabel yang dipartisi (PARTITION BY tanggal, CLUSTER BY kota): dashboard di 1 miliar baris turun dari US$3.682,68 jadi US$20,84 sebulan. Dialeknya beda: Senin awal minggu ditulis date(tanggal, 'weekday 0', '-6 days') di SQLite, date_trunc('week', tanggal) di DuckDB, DATE_TRUNC(tanggal, WEEK(MONDAY)) di BigQuery; DuckDB dan BigQuery punya QUALIFY, SQLite butuh CTE.

Yang akan kamu pelajari