ETL dan ELT adalah dua urutan untuk tiga langkah yang sama: Extract (ambil data dari sumber), Transform (bersihkan dan susun), Load (masukkan ke warehouse). Bedanya cuma di mana dan kapan langkah transform terjadi. Bayangin belanja sayur. Cara pertama: sayurnya kamu cuci dan potong di pasar, jadi yang masuk kulkas cuma potongan siap masak, kulit dan bonggolnya ditinggal. Cara kedua: semua kamu bawa pulang utuh, masuk kulkas apa adanya, lalu dipotong di dapur waktu mau masak. Besok mau masak menu lain, bahan utuhnya masih ada. Cara pertama itu ETL, cara kedua ELT. Pasarnya sumber data, kulkasnya warehouse, dapurnya mesin warehouse.
🧪 Tebakan cepat: load harian Toko Buku untuk tanggal 1 Oktober cuma
INSERT INTO penjualan SELECT .... Malam itu load-nya error di tengah, jadi dijalankan ulang. Setelah jalan dua kali, Bumi Manusia di Jakarta minggu 28 September terhitung berapa buku: 2, 4, atau 6? Tebak dulu, jawabannya ada di bagian "Load yang idempoten".
Tiga langkah yang sama
Pipeline Toko Buku dari pelajaran sebelumnya, dipecah per langkah:
| Langkah | Artinya | Di Toko Buku |
|---|---|---|
| Extract | membaca data dari sumber | SELECT pesanan satu hari dari MySQL aplikasi |
| Transform | membersihkan dan menyusun | buang baris dobel, kota NULL jadi Tidak diketahui, harga dari katalog, hitung minggu |
| Load | menulis ke tabel tujuan | INSERT ke warehouse |
Pipeline biasanya jalan per hari: tiap malam, satu load harian mengambil pesanan kemarin. Di Lab, sumber dan warehouse ditaruh di satu SQLite supaya bisa dijalankan bareng. Di dunia nyata keduanya database terpisah, dan sebuah script memindahkan hasil query dari yang satu ke yang lain.
ETL: bersih dulu, baru masuk
Di ETL, transform terjadi sebelum data sampai di warehouse. Warehouse cuma menerima hasil yang sudah bersih. Load harian 1 Oktober:
INSERT INTO penjualan
SELECT DISTINCT oi.order_id, oi.book_id,
date(o.created_at) AS tanggal,
date(o.created_at, 'weekday 0', '-6 days') AS minggu,
COALESCE(c.city, 'Tidak diketahui') AS kota,
b.title AS judul,
oi.qty,
b.price AS harga
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN customers c ON c.id = o.customer_id
JOIN books b ON b.id = oi.book_id
WHERE date(o.created_at) = '2026-10-01';
SELECT ... FROM order_items ...adalah extract: dia membaca tabel aplikasi.DISTINCT,COALESCE, danb.priceadalah transform, dan semuanya terjadi di dalam query yang membaca sumber, sebelum apa pun ditulis ke warehouse.INSERT INTO penjualanadalah load. 1 Oktober punya 3 baris item (7, 8, dan 9 yang dobel); yang masuk cuma 2.
Di dunia nyata, transform ETL sering ditulis di Python (pandas, dua pelajaran lagi) dan jalan di server sendiri. Idenya sama: warehouse gak pernah melihat data mentahnya.
ELT: masuk mentah, dibersihkan di warehouse
Di ELT, extract dan load jalan duluan, apa adanya. Transform terjadi di dalam warehouse, dengan SQL:
-- 1. Extract + Load: salin baris 1 Oktober tanpa diubah
INSERT INTO raw_order_lines
SELECT oi.id, o.id, o.created_at, c.name, c.city, b.id, b.title, oi.qty, oi.price
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN customers c ON c.id = o.customer_id
JOIN books b ON b.id = oi.book_id
WHERE date(o.created_at) = '2026-10-01';
-- 2. Transform: bangun ulang penjualan dari semua baris mentah
DROP TABLE IF EXISTS penjualan;
CREATE TABLE penjualan AS
SELECT DISTINCT r.order_id, r.book_id,
date(r.created_at) AS tanggal,
date(r.created_at, 'weekday 0', '-6 days') AS minggu,
COALESCE(r.city, 'Tidak diketahui') AS kota,
r.title AS judul,
r.qty,
b.price AS harga
FROM raw_order_lines r
JOIN books b ON b.id = r.book_id;
raw_order_linesadalah tabel raw (mentah): 19 baris persis seperti di sumber, termasuk baris dobel 9 dan harga 950000.- Langkah 2 membaca raw, bukan sumber. Aturan bersihnya sama dengan ETL, cuma tempatnya pindah ke warehouse.
- Kalau besok aturannya berubah, cukup jalankan ulang langkah 2. Data mentahnya masih ada.
Di mana pembersihan terjadi
| ETL | ELT | |
|---|---|---|
| Transform jalan di | sebelum warehouse: query ke sumber atau script Python | di dalam warehouse, pakai SQL |
| Yang tersimpan di warehouse | hasil bersih saja | data mentah, plus tabel bersih yang dibuat darinya |
| Aturan bersih ternyata salah | extract ulang dari sumber, kalau datanya masih ada | jalankan ulang SQL transform di atas raw |
| Butuh kolom yang dulu dibuang | gak bisa: kolomnya gak pernah dimuat | masih ada di raw |
| Tool yang sering dipakai | script Python, Informatica, Talend | Airbyte atau Fivetran untuk E dan L, dbt untuk T |
Kenapa ELT menang
Dulu warehouse mahal dan lambat, jadi data dirapikan dulu di server lain supaya yang masuk sekecil mungkin. Warehouse cloud seperti BigQuery dan Snowflake mengubah hitungannya: storage-nya murah, dan compute-nya (tenaga hitung) bisa dibesarkan sesaat untuk satu query berat lalu dimatikan lagi. Jadi lebih murah memuat semuanya mentah dan membersihkannya dengan SQL di sana. Bonusnya: SQL dikuasai analis juga, dan data mentahnya bisa diolah ulang kapan saja. Karena itu ELT lebih tepat kalau warehouse tujuannya punya compute besar.
ETL masih dipakai kalau:
- Ada data yang gak boleh masuk warehouse sama sekali, misalnya nomor HP atau alamat lengkap pelanggan. Kolom itu harus dibuang atau disamarkan di jalan.
- Sumbernya butuh diolah berat yang canggung di SQL, misalnya file XML dari supplier.
- Warehouse-nya kecil atau mahal per query.
Banyak tim memakai campurannya: buang kolom sensitif di jalan, sisanya dimuat mentah lalu dibersihkan di warehouse.
Load yang idempoten
Idempoten artinya dijalankan sekali atau berkali-kali, hasil akhirnya sama (kamu sudah ketemu istilah ini di pelajaran API Idempotency). Load harian pasti suatu saat dijalankan ulang: error di tengah, server restart, atau ada yang menekan tombol "run" dua kali.
Load ETL tadi cuma INSERT. Dijalankan dua kali untuk 1 Oktober, hasilnya di SQLite:
| Load 1 kali | Load 2 kali | |
|---|---|---|
Baris 1 Oktober di penjualan |
2 | 4 |
| Bumi Manusia, Jakarta, minggu 28 September | 2 | 4 |
| Laskar Pelangi, Jakarta, minggu 28 September | 3 | 3 |
Jawabannya 4. Itu jawaban tebakannya. Bumi Manusia menyalip Laskar Pelangi lagi, jawaban salah yang sama dengan pelajaran sebelumnya, kali ini gara-gara pipeline sendiri. Warehouse gak menolak: BigQuery dan Snowflake memang gak memaksakan primary key, jadi baris kembar masuk diam-diam.
Cara paling umum supaya idempoten: hapus dulu bagian yang mau diisi, baru isi. Bagian itu disebut partisi, di sini satu tanggal:
BEGIN;
DELETE FROM penjualan WHERE tanggal = '2026-10-01';
INSERT INTO penjualan
SELECT DISTINCT oi.order_id, oi.book_id,
date(o.created_at) AS tanggal,
date(o.created_at, 'weekday 0', '-6 days') AS minggu,
COALESCE(c.city, 'Tidak diketahui') AS kota,
b.title AS judul,
oi.qty,
b.price AS harga
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN customers c ON c.id = o.customer_id
JOIN books b ON b.id = oi.book_id
WHERE date(o.created_at) = '2026-10-01';
COMMIT;
DELETE ... WHERE tanggal = '2026-10-01'membuang apa pun yang pernah dimuat untuk tanggal itu, termasuk sisa load yang gagal.INSERTmengisinya lagi dari sumber. Dua kali, sepuluh kali, hasilnya tetap 2 baris.BEGINdanCOMMITmembungkus keduanya jadi satu transaksi: yang membaca warehouse gak pernah melihat tanggal itu dalam keadaan kosong.
Cara kedua: upsert, tulis kalau belum ada, ubah kalau sudah ada, berdasarkan kunci. Di SQLite dan PostgreSQL INSERT ... ON CONFLICT (order_id, book_id) DO UPDATE SET ..., di MySQL INSERT ... ON DUPLICATE KEY UPDATE, di BigQuery dan Snowflake MERGE. Di ELT, load ke raw juga harus idempoten: diulang tanpa DELETE, raw_order_lines jadi 22 baris. Jawaban di penjualan kebetulan tetap benar karena DISTINCT membuang baris kembar, tapi raw-nya sudah gak cocok dengan sumber.
⚠️ Jebakan yang sering ketemu
- Load cuma
INSERT. Jalan normal tiap malam, lalu suatu hari diulang dan angkanya dobel tanpa error. SelaluDELETEper partisi dulu, atau upsert. DELETEdanINSERTdi luar transaksi. KalauINSERTgagal, tanggal itu kosong dan laporan bilang "0 penjualan".- ETL membuang kolom yang nanti dibutuhkan. Harga yang benar-benar dibayar (
oi.price) gak dimuat kepenjualan. Pemilik minta omzet dengan harga bayar, dan datanya sudah gak ada di warehouse. - Mengira ELT berarti gak perlu bersih-bersih. Raw cuma bahan. Laporan harus membaca tabel yang sudah ditransform, bukan raw.
TL;DR: ETL dan ELT adalah tiga langkah yang sama, Extract, Transform, Load, dengan urutan beda. ETL membersihkan data sebelum masuk warehouse, jadi warehouse cuma menyimpan hasil bersih. ELT memuat data mentah ke tabel raw, lalu membersihkannya dengan SQL di dalam warehouse; ini pola utama sekarang karena compute warehouse cloud murah dan bisa dibesarkan, dan raw-nya bisa diolah ulang. ETL masih dipakai untuk data sensitif yang gak boleh masuk warehouse. Load harus idempoten: INSERT saja yang diulang bikin 1 Oktober jadi 4 baris dan Bumi Manusia jadi 4; DELETE per tanggal lalu INSERT dalam satu transaksi (atau upsert) membuat hasilnya tetap 2 baris, berapa kali pun dijalankan.