Worksheet 3: Terjemahan skema
Petakan setiap kolom TRIPS_RAW dan FACT_TRIPS ke tipe ClickHouse-nya dan terjemahkan tujuh ekspresi Snowflake, dengan umpan balik langsung pada setiap jawaban.
Perkiraan waktu: 20–25 menit Referensi: Snowflake vs ClickHouse — Bagian 2 (SQL Dialect Gaps)
Konsep
Pemetaan tipe dan terjemahan fungsi adalah bagian paling mekanis dari migrasi, tetapi juga paling rawan kesalahan jika dikerjakan sembarangan. Snowflake dan ClickHouse punya sistem tipe yang berbeda dengan semantik yang berbeda, dan memakai tipe yang salah bisa menyebabkan hilangnya presisi secara diam-diam, penyimpanan berlebihan, atau logika query yang rusak.
Prinsip utama:
-
Bersikap eksplisit soal presisi.
TIMESTAMP_NTZ(9)milik Snowflake punya presisi nanodetik.DateTimemilik ClickHouse hanya punya presisi detik — jangan pakai itu untuk kolom versi. GunakanDateTime64(3, 'UTC')untuk presisi milidetik (sesuai dengan sebagian besar kebutuhan nyata) atauDateTime64(9, 'UTC')untuk nanodetik. Ini penting untuk kebenaran hasil: jika kolom versiReplacingMergeTreehanya punya presisi detik, dua update yang tiba dalam detik yang sama menjadi non-deterministik — ClickHouse tidak bisa menentukan mana yang lebih baru. -
Gunakan tipe integer terkecil yang benar.
INTEGERmilik Snowflake adalahNUMBER(38, 0)— presisi tetap 38 digit yang disimpan sebagai nilai 128-bit. ClickHouse punya integer berlebar tetap:Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64. MemilihUInt8untukvendor_id(nilai 1–3) menghemat 7 byte per baris dibandingInt64. Pada 50 juta baris, itu 350MB. -
VARIANT → String. ClickHouse punya tipe
JSONnative (tersedia di v25.3+ sebagai production-stable), tetapi tipe itu dirancang untuk skema yang benar-benar dinamis di mana nama field dan strukturnya tidak diketahui saat tabel dibuat. Untuktrip_metadatadi lab ini, strukturnya sudah diketahui (driver.rating,app.surge_multiplier, dan sebagainya) — pendekatan yang lebih baik adalah meratakan lebih dulu menjadi kolom bertipe selama migrasi, atau menyimpannya sebagaiStringdan memakaiJSONExtract*saat query. Gunakan tipeJSONketika Anda benar-benar tidak bisa memprediksi skemanya: misalnya, mengingest payload event pelanggan yang arbitrer di mana setiap event punya field berbeda. ("Meratakan lebih dulu menjadi kolom bertipe" berarti mengekstrak field menjadi kolom tingkat atas yang terpisah selama ETL — seperti caraFACT_TRIPS.driver_ratingdihasilkan daritrip_metadata— bukan membungkus blob JSON itu sendiri dalam sebuahTuple. KolomTupletetap mengikat diri pada satu set field yang tetap, sehingga ia rusak begitu metadata sebuah perjalanan tidak cocok dengan bentuk itu.) -
Presisi float.
FLOATmilik Snowflake dipetakan keFloat64di ClickHouse. Untuk nilai uang yang menuntut aritmetika desimal eksak, gunakanDecimal(18, 2)— tetapi untuk lab ini,Float64sudah cukup untuk menyamai sumbernya. (Ini adalah default, bukan aturan bahwa setiap kolomFLOATmengambilFloat64tanpa memandang rentangnya: sebuah kolom sepertidriver_rating, yang nilainya berjalan 1.0–5.0 pada satu angka desimal, cukup nyaman masuk ke ~7 digit signifikan milikFloat32— pilihan di sana bergantung pada nullability, bukan pada presisi yang dilindungi Aturan 4 untuk nilai uang.) -
LowCardinality()— optimasi khusus ClickHouse. Membungkus sebuah tipe dalamLowCardinality(String)(atauLowCardinality(UInt8), dan sebagainya) memberitahu ClickHouse untuk memakai dictionary encoding bagi kolom itu — nilai disimpan sebagai referensi integer ke sebuah dictionary, bukan sebagai string yang berulang. Ini biasanya memberi perbaikan kompresi 2–5x danGROUP BYyang lebih cepat pada kolom string dengan kurang dari ~10.000 nilai berbeda. Snowflake tidak punya padanannya; ia menanganinya secara otomatis. Kandidat yang baik di lab ini:pickup_borough(6 nilai),payment_type(6 nilai),vehicle_type,vendor_name.
Latihan: pemetaan tipe untuk TRIPS_RAW
Petakan setiap kolom dari NYC_TAXI_DB.RAW.TRIPS_RAW ke tipe ClickHouse-nya. TRIP_ID sudah
diisi sebagai contoh: String adalah pilihan idiomatis saat bermigrasi dari VARCHAR(36) — ia
tidak butuh casting, mendukung setiap fungsi string, dan menghindari overhead parsing UUID saat
insert, meskipun ClickHouse juga punya tipe UUID native.
Latihan: pemetaan tipe untuk FACT_TRIPS
FACT_TRIPS menambahkan kolom terhitung/turunan yang ditambahkan oleh pipeline dbt. Sebagian besar
kolom mengulang keputusan TRIPS_RAW; DRIVER_RATING dan UPDATED_AT adalah yang baru.
DRIVER_RATING sering kali NULL (tidak ada rating yang diberikan). Di ClickHouse, Nullable(Float64)
punya sedikit overhead performa dibanding kolom non-nullable — sebuah bitmask terpisah
disimpan bersama data untuk melacak baris mana yang null. Pilihan untuk kolom ini adalah
antara Nullable(Float32) (semantik null yang eksplisit) dan Float32 polos dengan nilai sentinel
seperti -1.0 (lebih cepat, kurang konvensional). Lab ini memakai Nullable(Float32) demi
kebenaran hasil.
Latihan: terjemahan fungsi
Terjemahkan setiap ekspresi Snowflake ke padanan ClickHouse-nya. Ini datang langsung
dari Q1–Q7 di 01-setup-snowflake/queries/. Tiga dari delapan — QUALIFY, MERGE INTO,
dan pembacaan stream CDC — tidak punya ekspresi satu baris sebagai jawabannya, jadi ketiganya
dikerjakan sebagai pertanyaan di bawah tabel.
Pertanyaan refleksi
Setelah tabel di atas terisi, kerjakan pertanyaan berikut. Tiga di antaranya berasal dari
terjemahan Latihan 3 yang butuh lebih dari satu baris untuk dijawab; tiga lainnya adalah
"Non-Obvious Translation Decisions" dari worksheet sumber — penalaran di balik pilihan tipe
TRIP_METADATA, FARE_AMOUNT, dan PICKUP_LOCATION_ID di atas.
Loading worksheet...
Pindahkan ke migration-plan.md
Salin keputusan tipe Anda dan setiap catatan terjemahan yang tidak kasatmata ke Bagian 5 dari
migration-plan.md dan centang:
- [ ] Schema translation: completedWorksheet 2: Desain sort key (ORDER BY)
Turunkan ORDER BY untuk setiap tabel NYC Taxi dari workload query-nya, dengan umpan balik langsung pada setiap jawaban.
Worksheet 4: Rencana gelombang migrasi
Urutkan sepuluh objek NYC Taxi ke dalam gelombang migrasi dan beri nilai kompleksitas masing-masing, dengan umpan balik langsung pada setiap jawaban.