Google BigQuery - Bài học 9: GoogleSQL vs Legacy SQL – Các kiểu dữ liệu đặc trưng trong BigQuery và lưu ý về INT64, FLOAT64, NUMERIC
Chào anh em! Sau khi đã hoàn tất Phần 1 với những kiến thức nền tảng vững như bàn thạch về hạ tầng (Colossus, Capacitor, Dremel, Jupiter) và cách quy hoạch dự án, hôm nay chúng ta chính thức bước sang Phần 2: Làm chủ GoogleSQL & Xử lý dữ liệu bán cấu trúc.
Nếu như các bài học trước giúp chúng ta hiểu cách vận hành một hệ thống Cloud Data Warehouse, thì từ bài học này trở đi, chúng ta sẽ mài giũa vũ khí sắc bén nhất của một Data Engineer hay Backend Developer khi làm việc với BigQuery: Ngôn ngữ truy vấn.
Nhiều anh em mới bước chân vào thế giới BigQuery thường gặp phải một cú sốc văn hóa nhỏ với cú pháp SQL của nó, đặc biệt là sự khác biệt giữa hai trường phái cú pháp cũ và mới, cùng những cái bẫy chết người về kiểu dữ liệu số học. Hôm nay, chúng ta sẽ cùng nhau bóc trần những khác biệt đó!
1. Cuộc chiến lịch sử: GoogleSQL (Standard SQL) vs Legacy SQL
Trước khi BigQuery trở thành chuẩn mực như hiện tại, Google từng sử dụng một cú pháp SQL độc quyền riêng gọi là Legacy SQL (được thiết kế từ những ngày đầu khi BigQuery còn là nội bộ bên trong Google với tên gọi Dremel).
Tuy nhiên, từ năm 2016, Google đã tung ra chuẩn GoogleSQL (trước đây gọi là Standard SQL), tuân thủ tuyệt đối theo chuẩn quốc tế ANSI SQL:2011.
Bảng so sánh nhanh "Sống còn" giữa hai chuẩn cú pháp:
| Tiêu chí | Legacy SQL (Chuẩn cũ - ĐÃ LỖI THỜI) | GoogleSQL (Chuẩn mới - BẮT BUỘC DÙNG) |
|---|---|---|
| Cú pháp định danh bảng | Dùng dấu ngoặc vuông và dấu chấm phẩy lạ đời: [project:dataset.table] |
Chuẩn ANSI quốc tế, dùng dấu nháy ngược (backticks): `project.dataset.table` |
| Xử lý mảng (Array / Repeated) | Cực kỳ cồng kềnh, dùng hàm FLATTEN() hoặc NEST() thủ công. |
Hỗ trợ cực mạnh mẽ và tự nhiên với mệnh đề UNNEST() và các cấu trúc STRUCT. |
| Phép chia số nguyên (Integer Division) | 5 / 2 ra kết quả bằng 2 (tự động ép kiểu bỏ phần dư). |
5 / 2 ra kết quả chuẩn xác là 2.5 (kiểu FLOAT64). Muốn chia lấy phần nguyên phải dùng hàm DIV(5, 2). |
| Hỗ trợ hàm (Functions) | Ít hàm, tên hàm không đồng nhất. | Thư viện hàm khổng lồ, hỗ trợ đầy đủ Regular Expressions, JSON, GIS, Window Functions. |
| Khuyến nghị từ Google | Tuyệt đối KHÔNG DÙNG cho các dự án mới. | Chuẩn mực vàng, được bật mặc định trong mọi Project mới. |
Quy tắc vàng: Trong bất kỳ câu lệnh nào, hãy luôn đảm bảo bạn đã bật GoogleSQL. Nếu bạn dùng
bqCLI mà quên cấu hình file~/.bigqueryrcnhư chúng ta đã học ở Bài 7, hoặc giao diện web vô tình chọn nhầm Legacy SQL, bạn sẽ thấy hàng loạt lỗi cú pháp khó hiểu. Hãy luôn nhớ: Dùng dấu nháy ngược (`) bao quanh tên bảng!
2. Hệ thống kiểu dữ liệu trong BigQuery: Cẩn thận kẻo "mất tiền oan" vì ép kiểu sai
Khi chuyển đổi dữ liệu từ cơ sở dữ liệu OLTP truyền thống (như MySQL, PostgreSQL) sang BigQuery, một trong những nguyên nhân khiến câu lệnh SQL chạy ra kết quả sai lệch hoặc tính toán tiền bạc bị lệch vài đồng chính là việc hiểu lơ mơ về các kiểu dữ liệu số học.
Hãy cùng soi kỹ 3 kiểu dữ liệu số phổ biến nhất: INT64, FLOAT64, và NUMERIC (DECIMAL).
2.1. Kiểu số nguyên: INT64 (64-bit Signed Integer)
-
Phạm vi: Từ đến .
-
Đặc điểm: Tương đương với
BIGINTtrong PostgreSQL hoặcBIGINTtrong MySQL. Đây là kiểu dữ liệu hoàn hảo cho các khóa chính (id), số lượng đếm (count), hoặc mã định danh. -
Lưu ý: BigQuery không có các kiểu dữ liệu nhỏ hơn như
INT32,INT16hayTINYINTở dạng lưu trữ vật lý tối ưu độc lập; mọi số nguyên bên trong Capacitor đều được lưu trữ và tối ưu dưới dạng 64-bit (hoặc được nén cực tốt nếu giá trị nhỏ nhờ thuật toán RLE).
2.2. Kiểu số thực trôi: FLOAT64 (Double Precision Floating-Point)
-
Phạm vi: Số thực dấu phẩy động chuẩn IEEE 754 (64-bit).
-
Đặc điểm: Cực kỳ nhanh khi tính toán bằng phần cứng CPU, phù hợp cho các bài toán khoa học, tọa độ địa lý (
GEOGRAPHY), xác suất, hoặc phân tích Machine Learning. -
Cạm bẫy chí mạng (Precision Loss): Không bao giờ dùng
FLOAT64để lưu trữ tiền tệ (Currency) hoặc tài chính!Vì bản chất lưu trữ nhị phân (binary floating-point), các phép tính cộng trừ trên kiểu
FLOAT64thường gây ra hiện tượng sai số làm tròn cực kỳ nhỏ (ví dụ:0.1 + 0.2có thể ra0.30000000000000004thay vì0.3). Thử tưởng tượng hệ thống tài chính của công ty bạn lệch vài xu sau hàng triệu giao dịch, kế toán sẽ "gọi hồn" bạn ngay lập tức!
2.3. Kiểu số chính xác tuyệt đối: NUMERIC và BIGNUMERIC (Exact Numeric)
Để giải quyết bài toán sai số của FLOAT64 trong thương mại điện tử và tài chính, GoogleSQL cung cấp kiểu dữ liệu NUMERIC:
-
NUMERIC(hayDECIMAL): Số thập phân có độ chính xác tuyệt đối với 38 chữ số phần nguyên và 9 chữ số phần thập phân (Lưu trữ cố định trong 16 bytes). Hoàn hảo cho việc tính tổng doanh thu đơn hàng, giá tiền, chiết khấu. -
BIGNUMERIC: Phiên bản "hạng nặng" hơn với 38 chữ số phần nguyên và tới 38 chữ số phần thập phân dành cho các hệ thống tài chính quy mô toàn cầu hoặc tiền mã hóa (crypto) đòi hỏi độ chính xác cực cao. -
Quy tắc thực chiến: Bất cứ khi nào cột dữ liệu của bạn liên quan đến Tiền tệ (Price, Amount, Revenue, Discount), hãy ép buộc schema của bảng phải là kiểu
NUMERIC, tuyệt đối tránh xaFLOAT64hayDOUBLE.
3. Các kiểu dữ liệu thời gian (Temporal Types): Cơn ác mộng lệch múi giờ
Trong hệ thống Backend, việc lưu trữ thời gian luôn là một "cục máu đông", và khi đổ vào BigQuery, nó càng trở nên phức tạp nếu bạn không phân biệt rõ 4 anh em nhà thời gian sau đây:
-
DATE: Chỉ chứa ngày, tháng, năm (Ví dụ:2026-10-18). Không có giờ, phút, giây, không có múi giờ. Thường dùng để làm cột phân vùng bảng (Partitioning by Date). -
TIME: Chỉ chứa giờ, phút, giây, micro-second (Ví dụ:14:30:00). Không có thông tin ngày tháng hay múi giờ. -
DATETIME: Gồm cả ngày tháng và giờ phút giây (Ví dụ:2026-10-18 14:30:00). Nó đại diện cho "thời gian tại chỗ" (Wall-clock time), mang tính chất tương đối và không gắn liền với bất kỳ múi giờ cụ thể nào. -
TIMESTAMP: Đại diện cho một thời điểm tuyệt đối trên trục thời gian vũ trụ, được tính chính xác bằng số micro-second trôi qua kể từ mốc Epoch (00:00:00 UTC ngày 1 tháng 1 năm 1970), luôn gắn liền với múi giờ UTC (+0).
Mẹo xử lý múi giờ tại Việt Nam (Asia/Ho_Chi_Minh vs UTC):
Hầu hết các hệ thống Backend đặt tại Việt Nam lưu created_at ở múi giờ UTC+7. Khi đẩy lên BigQuery, kiểu TIMESTAMP sẽ tự động quy đổi về chuẩn UTC. Nếu bạn muốn viết câu lệnh thống kê theo ngày giờ địa phương của Việt Nam (Asia/Ho_Chi_Minh), hãy dùng hàm chuyển đổi múi giờ DATETIME():
SQL
-- Chuyển đổi một cột TIMESTAMP chuẩn UTC sang múi giờ Việt Nam để nhóm theo ngày đúng chuẩn thực tế
SELECT
DATETIME(created_at, 'Asia/Ho_Chi_Minh') AS vn_local_time,
DATE(DATETIME(created_at, 'Asia/Ho_Chi_Minh')) AS vn_local_date,
COUNT(*) AS total_orders
FROM `my-project.core_dwh.fact_orders`
WHERE created_at >= TIMESTAMP('2026-10-01 00:00:00', 'Asia/Ho_Chi_Minh')
GROUP BY vn_local_date
ORDER BY vn_local_date DESC;
Việc làm chủ hàm DATETIME(timestamp_col, 'Time_Zone') sẽ giúp bạn cứu nguy cho hàng loạt báo cáo bị lệch số liệu giữa 00h00 đêm của ngày hôm trước và hôm sau do chênh lệch múi giờ UTC!
4. Các kiểu dữ liệu định danh và định dạng nâng cao khác
Ngoài số và thời gian, GoogleSQL còn cung cấp các kiểu dữ liệu chuyên dụng rất đáng chú ý:
-
BOOL(Boolean): Nhận giá trịTRUE,FALSEhoặcNULL. -
BYTES: Lưu trữ dữ liệu nhị phân thô (Raw binary data), thường dùng khi bạn cần mã hóa băm mật khẩu, lưu chuỗi Byte hoặc payload mã hóa HMAC. -
GEOGRAPHY: Kiểu dữ liệu không gian 2 chiều tuân thủ chuẩn OGC (Open Geospatial Consortium), cho phép biểu diễn điểm (Point), đường (LineString), hoặc vùng (Polygon) trên bề mặt Trái Đất dạng cầu. Cực kỳ mạnh mẽ cho các bài toán tính khoảng cách giao hàng, định vị tài xế shipper mà chúng ta sẽ tìm hiểu ở Bài 23 (BigQuery GIS).
Tổng kết Bài học 9
Trong bài học đầu tiên của Phần 2 này, chúng ta đã nắm giữ những nền tảng cú pháp và kiểu dữ liệu quan trọng nhất của GoogleSQL:
-
Luôn sử dụng GoogleSQL (Standard SQL) với chuẩn định danh bằng dấu nháy ngược (
`) và cú pháp hiện đại. -
Cẩn trọng với kiểu dữ liệu số: Tuyệt đối dùng
NUMERICcho tiền tệ/tài chính để tránh sai số dấu phẩy động củaFLOAT64. -
Hiểu rõ tường tận sự khác biệt giữa
DATETIME(thời gian tương đối) vàTIMESTAMP(thời điểm tuyệt đối UTC), biết cách dùng hàmDATETIME(col, 'Asia/Ho_Chi_Minh')để xử lý chính xác múi giờ tại Việt Nam.
Nhưng sức mạnh thực sự của GoogleSQL không chỉ nằm ở các kiểu dữ liệu phẳng này. Điều gì sẽ xảy ra khi bảng của bạn không còn phẳng nữa, mà bên trong mỗi dòng đơn hàng lại chứa một mảng danh sách sản phẩm hoặc một cấu trúc JSON phức tạp từ API đổ về mà không cần phải JOIN rườm rà?
Hẹn gặp lại anh em ở Bài học 10: Tư duy Denormalization – Tại sao trong BigQuery người ta lại thích gộp bảng thay vì tách bảng chuẩn hóa 3NF?!
All Rights Reserved