Snowflake MigrationClickHouse Workshops
Các worksheet lập kế hoạch

Worksheet 3: Dịch schema

Ánh xạ mọi cột của TRIPS_RAW và FACT_TRIPS sang kiểu ClickHouse và dịch bảy biểu thức Snowflake, với phản hồi ngay lập tức cho mọi câu trả lời.

Thời lượng dự kiến: 20–25 phút Tài liệu tham chiếu: Snowflake so với ClickHouse — Phần 2 (SQL Dialect Gaps)

Khái niệm

Ánh xạ kiểu dữ liệu và dịch hàm là phần máy móc nhất của một cuộc di chuyển, nhưng cũng dễ sai nhất nếu làm cẩu thả. Snowflake và ClickHouse có những hệ kiểu khác nhau với ngữ nghĩa khác nhau, và dùng sai kiểu có thể gây mất độ chính xác âm thầm, lưu trữ quá mức, hoặc logic truy vấn bị hỏng.

Các nguyên tắc chính:

  1. Hãy tường minh về độ chính xác. TIMESTAMP_NTZ(9) của Snowflake có độ chính xác nanosecond. DateTime của ClickHouse chỉ có độ chính xác giây — đừng dùng nó cho các cột version. Dùng DateTime64(3, 'UTC') cho độ chính xác millisecond (khớp với phần lớn yêu cầu thực tế) hoặc DateTime64(9, 'UTC') cho nanosecond. Điều này ảnh hưởng đến tính đúng đắn: nếu một cột version của ReplacingMergeTree chỉ có độ chính xác giây, hai lần cập nhật đến trong cùng một giây sẽ không xác định được — ClickHouse không thể xác định cái nào mới hơn.

  2. Dùng kiểu số nguyên nhỏ nhất mà vẫn đúng. INTEGER của Snowflake là NUMBER(38, 0) — độ chính xác cố định 38 chữ số, lưu dưới dạng một giá trị 128-bit. ClickHouse có các số nguyên độ rộng cố định: Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64. Chọn UInt8 cho vendor_id (giá trị 1–3) tiết kiệm 7 byte mỗi dòng so với Int64. Ở 50M dòng, đó là 350MB.

  3. VARIANT → String. ClickHouse có kiểu JSON native (có từ v25.3+ ở mức production-stable), nhưng nó được thiết kế cho những schema thực sự động, nơi tên trường và cấu trúc chưa biết tại thời điểm tạo bảng. Với trip_metadata trong lab này, cấu trúc đã biết (driver.rating, app.surge_multiplier, v.v.) — cách tốt hơn là làm phẳng trước thành các cột có kiểu trong lúc di chuyển, hoặc lưu dưới dạng String và dùng JSONExtract* tại thời điểm truy vấn. Hãy dùng kiểu JSON khi bạn thực sự không thể dự đoán schema: ví dụ, khi nạp các payload sự kiện khách hàng tùy ý, nơi mọi sự kiện có các trường khác nhau. ("Làm phẳng trước thành các cột có kiểu" nghĩa là trích các trường thành những cột riêng ở cấp cao nhất trong lúc ETL — cách mà FACT_TRIPS.driver_rating được sinh ra từ trip_metadata — không phải bọc chính khối JSON trong một Tuple. Một cột Tuple vẫn cam kết với một tập trường cố định, nên nó vỡ ngay khi metadata của một chuyến đi không khớp hình dạng đó.)

  4. Độ chính xác số thực. FLOAT của Snowflake ánh xạ sang Float64 trong ClickHouse. Với các số tiền cần phép tính thập phân chính xác, hãy dùng Decimal(18, 2) — nhưng với lab này, Float64 là đủ để khớp với nguồn. (Đây là mặc định, không phải một nguyên tắc rằng mọi cột FLOAT đều lấy Float64 bất kể khoảng giá trị: một cột như driver_rating, với giá trị chạy từ 1.0–5.0 ở một chữ số thập phân, nằm thoải mái trong ~7 chữ số có nghĩa của Float32 — lựa chọn ở đó phụ thuộc vào tính nullable, không phải độ chính xác mà Nguyên tắc 4 đang bảo vệ cho tiền tệ.)

  5. LowCardinality() — tối ưu hóa chỉ có ở ClickHouse. Bọc một kiểu trong LowCardinality(String) (hoặc LowCardinality(UInt8), v.v.) yêu cầu ClickHouse dùng mã hóa từ điển cho cột đó — các giá trị được lưu dưới dạng tham chiếu số nguyên tới một từ điển thay vì các chuỗi lặp lại. Cách này thường cho cải thiện độ nén 2–5x và GROUP BY nhanh hơn trên các cột chuỗi có ít hơn ~10,000 giá trị phân biệt. Snowflake không có tương đương; nó xử lý việc này tự động. Các ứng viên tốt trong lab này: pickup_borough (6 giá trị), payment_type (6 giá trị), vehicle_type, vendor_name.

Bài tập: ánh xạ kiểu cho TRIPS_RAW

Ánh xạ từng cột từ NYC_TAXI_DB.RAW.TRIPS_RAW sang kiểu ClickHouse của nó. TRIP_ID đã được điền làm ví dụ: String là cách làm quen dùng khi di chuyển từ VARCHAR(36) — nó không cần cast, hỗ trợ mọi hàm chuỗi, và tránh chi phí phân tích UUID khi insert, ngay cả khi ClickHouse cũng có kiểu UUID native.

Bài tập: ánh xạ kiểu cho FACT_TRIPS

FACT_TRIPS thêm các cột tính toán/dẫn xuất do pipeline dbt bổ sung. Phần lớn các cột lặp lại một quyết định của TRIPS_RAW; DRIVER_RATING và UPDATED_AT là mới.

DRIVER_RATING thường là NULL (không có đánh giá). Trong ClickHouse, Nullable(Float64) có chi phí hiệu năng nhẹ so với một cột non-nullable — một bitmask riêng được lưu cùng dữ liệu để theo dõi những dòng nào là null. Lựa chọn cho cột này là giữa Nullable(Float32) (ngữ nghĩa null tường minh) và một Float32 trần với một giá trị sentinel như -1.0 (nhanh hơn, ít quy ước hơn). Lab này dùng Nullable(Float32) để đảm bảo tính đúng đắn.

Bài tập: dịch hàm

Dịch từng biểu thức Snowflake sang biểu thức ClickHouse tương đương. Chúng đến trực tiếp từ Q1–Q7 trong 01-setup-snowflake/queries/. Ba trong tám — QUALIFY, MERGE INTO, và việc đọc CDC stream — không có một biểu thức một dòng làm đáp án, nên chúng được làm dưới dạng câu hỏi bên dưới bảng.

Câu hỏi suy ngẫm

Khi các bảng ở trên đã được điền, hãy làm qua những câu này. Ba câu đến từ các bản dịch của Bài tập 3 mà đáp án cần nhiều hơn một dòng; ba câu là phần "Non-Obvious Translation Decisions" của worksheet nguồn — lập luận đằng sau các lựa chọn kiểu cho TRIP_METADATA, FARE_AMOUNT và PICKUP_LOCATION_ID ở trên.

Loading worksheet...

Chuyển sang migration-plan.md

Sao các quyết định về kiểu dữ liệu và mọi ghi chú dịch không hiển nhiên của bạn vào Phần 5 của migration-plan.md và tick ô:

- [ ] Schema translation: completed

Trên trang này

Track your progress?

Optional. We email a link to confirm your address; progress records once you open it.

Please use your work email address, not a personal one.

Progress tracking also requires accepting the current Terms of Service in Privacy settings.

VI