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:
-
Hãy tường minh về độ chính xác.
TIMESTAMP_NTZ(9)của Snowflake có độ chính xác nanosecond.DateTimecủa ClickHouse chỉ có độ chính xác giây — đừng dùng nó cho các cột version. DùngDateTime64(3, 'UTC')cho độ chính xác millisecond (khớp với phần lớn yêu cầu thực tế) hoặcDateTime64(9, 'UTC')cho nanosecond. Điều này ảnh hưởng đến tính đúng đắn: nếu một cột version củaReplacingMergeTreechỉ 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. -
Dùng kiểu số nguyên nhỏ nhất mà vẫn đúng.
INTEGERcủ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ọnUInt8chovendor_id(giá trị 1–3) tiết kiệm 7 byte mỗi dòng so vớiInt64. Ở 50M dòng, đó là 350MB. -
VARIANT → String. ClickHouse có kiểu
JSONnative (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ớitrip_metadatatrong 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ạngStringvà dùngJSONExtract*tại thời điểm truy vấn. Hãy dùng kiểuJSONkhi 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ộtTuple. Một cộtTuplevẫ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 đó.) -
Độ chính xác số thực.
FLOATcủa Snowflake ánh xạ sangFloat64trong 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ùngDecimal(18, 2)— nhưng với lab này,Float64là đủ để 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ộtFLOATđều lấyFloat64bấ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ủaFloat32— 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ệ.) -
LowCardinality()— tối ưu hóa chỉ có ở ClickHouse. Bọc một kiểu trongLowCardinality(String)(hoặcLowCardinality(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 BYnhanh 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: completedWorksheet 2: Thiết kế sort key (ORDER BY)
Suy ra một ORDER BY cho từng bảng NYC Taxi từ workload truy vấn của nó, với phản hồi ngay lập tức cho mọi câu trả lời.
Worksheet 4: Kế hoạch các đợt di chuyển
Sắp xếp mười đối tượng NYC Taxi vào các đợt di chuyển và xếp hạng độ phức tạp của từng đối tượng, với phản hồi ngay lập tức cho mọi câu trả lời.