0

Google BigQuery - Bài học 27: Table Clustering (Phân cụm bảng) – Sắp xếp dữ liệu đa chiều để cắt giảm chi phí quét tối đa

Chào anh em! Ở Bài học 26, chúng ta đã nắm lòng cách sử dụng Table Partitioning để chia nhỏ bảng theo thời gian hoặc khoảng số nguyên, giúp hệ thống bỏ qua hàng ngàn phân vùng rác và chỉ quét đúng dữ liệu của ngày cần thiết.

Nhưng hãy thử đặt ra một tình huống thực tế:

Bạn đã phân vùng bảng fact_orders theo ngày (DATE(created_at)). Hôm nay là ngày 18/10/2026, phân vùng của ngày hôm nay có khoảng 50 triệu dòng dữ liệu. Sếp yêu cầu bạn chạy một câu lệnh tìm kiếm:

SQL

SELECT * 
FROM `my-project.core_dwh.fact_orders`
WHERE DATE(created_at) = '2026-10-18'
  AND customer_id = 889922; -- Tìm kiếm theo mã khách hàng cụ thể

  • Điều gì xảy ra? BigQuery đã mở đúng "ngăn kéo" của ngày 18/10/2026 (Partition Pruning hoạt động hoàn hảo). Tuy nhiên, bên trong ngăn kéo 50 triệu dòng đó, dữ liệu được vứt lộn xộn không theo trật tự nào. Để tìm ra dòng có customer_id = 889922, Dremel vẫn buộc phải quét toàn bộ 50 triệu dòng nằm trong ngăn kéo đó!

Chỉ phân vùng theo thời gian thôi là chưa đủ đối với các tiêu chí tìm kiếm đa dạng. Đó là lúc vũ khí đồng hành tối thượng xuất hiện: Table Clustering (Phân cụm bảng). Hãy cùng mổ xẻ xem Clustering sắp xếp dữ liệu thần kỳ thế nào nhé!

1. Table Clustering là gì? Định nghĩa qua ví dụ thực tế

Table Clustering là kỹ thuật tự động sắp xếp lại trật tự vật lý của dữ liệu bên trong một bảng (hoặc bên trong từng phân vùng) dựa trên giá trị của tối đa 4 cột mà bạn chỉ định (gọi là Clustering Columns).

Trực quan hóa qua danh bạ điện thoại:

  • Partitioning: Giống như bạn chia danh bạ ra thành từng cuốn sổ theo Từng tháng trong năm (Tháng 1, Tháng 2...).

  • Clustering: Giống như bên trong cuốn sổ của tháng đó, các số điện thoại được sắp xếp theo thứ tự bảng chữ cái A-Z của tên người dùng.

  • Khi bạn muốn tìm số của "Nguyễn Văn A", bạn mở đúng cuốn sổ tháng đó (Partition Pruning) rồi lật ngay đến vần N (Block Pruning nhờ Clustering) mà không cần phải dò từ trang đầu đến trang cuối!

2. Cơ chế hoạt động bên dưới: Sự kết hợp hoàn hảo với Capacitor và Min/Max Block Pruning

Để hiểu tại sao Clustering lại giúp cắt giảm chi phí quét dữ liệu khủng khiếp như vậy, chúng ta phải nhớ lại kiến thức ở Bài học 3 (Định dạng Capacitor):

  1. Khi bạn tạo một bảng có bật Clustering (ví dụ trên cột customer_id và status), bộ máy ghi dữ liệu của BigQuery sẽ gom các dòng có giá trị customer_id gần giống nhau lại và sắp xếp chúng nằm cạnh nhau trong các khối dữ liệu nhỏ (Data Blocks / Row Groups) trên ổ đĩa Colossus.

  2. Ở phần tiêu đề (Header) của mỗi khối dữ liệu đó, Capacitor luôn ghi nhớ sẵn hai thông số quan trọng: Min Value và Max Value của cột được Clustered.

  3. Khi bạn chạy câu lệnh WHERE customer_id = 889922, Dremel đọc phần Header của tất cả các khối dữ liệu:

    • Khối 1: customer_id [Min: 1000, Max: 50000] →\rightarrow Không chứa 889922 →\rightarrow Bỏ qua ngay lập tức (Block Pruning)!

    • Khối 15: customer_id [Min: 880000, Max: 900000] →\rightarrow Chứa giá trị cần tìm →\rightarrow Dremel mới mở khối này ra đọc.

Nhờ cơ chế này, thay vì quét toàn bộ 50 triệu dòng trong phân vùng ngày hôm đó, BigQuery chỉ phải đọc đúng vài khối dữ liệu thực sự chứa customer_id đó, giúp giảm lượng dữ liệu quét xuống hàng chục, thậm chí hàng trăm lần!

3. Thực chiến: Tạo bảng kết hợp cả Partitioning và Clustering

Trong các kiến trúc Data Warehouse hiện đại, công thức vàng để tối ưu hóa hiệu năng và chi phí là kết hợp cả Partitioning (theo thời gian) và Clustering (theo các cột thường xuyên dùng để lọc/JOIN).

Câu lệnh DDL chuẩn mực:

SQL

CREATE TABLE `my-project.core_dwh.fact_orders_optimized` (
    order_id INT64,
    customer_id INT64,
    store_id INT64,
    status STRING,
    total_amount NUMERIC,
    created_at TIMESTAMP
)
-- 1. Phân vùng chính theo ngày tạo đơn
PARTITION BY DATE(created_at)
-- 2. Phân cụm đa chiều theo thứ tự ưu tiên (Tối đa 4 cột)
CLUSTER BY customer_id, store_id, status
OPTIONS (
    description = "Bảng tối ưu với Partition theo ngày kết hợp Clustering đa chiều",
    require_partition_filter = TRUE
);

4. Bốn nguyên tắc "Vàng" khi thiết kế cột Clustering

Không phải cứ thích cột nào là đưa vào Clustering cột đó. Hãy tuân thủ 4 nguyên tắc kỹ thuật sau để không bị phản tác dụng:

Nguyên tắc 1: Thứ tự các cột cực kỳ quan trọng (Column Order Matters)

Khi bạn khai báo CLUSTER BY col_A, col_B, col_C, BigQuery sẽ ưu tiên sắp xếp theo col_A trước, sau đó mới đến col_B bên trong nhóm của col_A.

  • Do đó, hãy đặt cột nào có tính lọc mạnh nhất (hoặc thường xuyên xuất hiện nhất trong mệnh đề WHERE và JOIN) lên hàng đầu tiên.

Nguyên tắc 2: Chọn cột có độ phân tán cao (High Cardinality)

Clustering phát huy hiệu quả tuyệt đối với các cột có nhiều giá trị phân biệt khác nhau như customer_id, device_id, order_id, sku_id.

  • Đừng bao giờ đưa các cột có quá ít giá trị (Low Cardinality) như cột is_active (chỉ có TRUE/FALSE) hoặc cột gender (chỉ có Nam/Nữ) vào làm cột Clustering, vì nó không giúp capacitor phân tách được các khối dữ liệu rõ ràng.

Nguyên tắc 3: Tối đa 4 cột Clustering cho mỗi bảng

Google BigQuery cho phép bạn chọn tối đa 4 cột trong mệnh đề CLUSTER BY. Tuy nhiên, kinh nghiệm thực chiến cho thấy bạn chỉ nên chọn từ 2 đến 3 cột quan trọng nhất để bộ máy tối ưu hóa đạt hiệu suất cao nhất.

Nguyên tắc 4: Tự động sắp xếp ngầm (Automatic Reclustering)

Khác với một số hệ thống Database truyền thống đòi hỏi bạn phải tự thủ công chạy lệnh OPTIMIZE TABLE hay REINDEX định kỳ, BigQuery có cơ chế Background Reclustering tự động chạy ngầm trên nền tảng cơ sở hạ tầng của họ để sắp xếp lại các khối dữ liệu mới nạp vào mà không làm gián đoạn bất kỳ hoạt động truy vấn nào của bạn.

Tổng kết Bài học 27

Table Clustering là mảnh ghép hoàn hảo tiếp theo giúp bạn hoàn thiện kỹ năng thiết kế bảng tối ưu trên Google BigQuery:

  1. Sắp xếp đa chiều: Tự động gom nhóm dữ liệu vật lý bên trong phân vùng dựa trên tối đa 4 cột chỉ định.

  2. Block Pruning thông minh: Giúp Dremel bỏ qua hàng loạt khối dữ liệu không liên quan thông qua giá trị Min/Max ở phần Header của file Capacitor.

  3. Công thức kết hợp: Luôn đi kèm Partitioning (theo thời gian) với Clustering (theo ID/Trạng thái) để đạt hiệu năng truy vấn siêu tốc và chi phí tối thiểu.

Tuy nhiên, khi các câu lệnh SQL bắt đầu trở nên phức tạp với nhiều điều kiện JOIN, GROUP BY và lượng dữ liệu lớn, làm thế nào để bạn tự đọc và phân tích xem câu lệnh của mình đang bị nghẽn ở bước nào (Execution Plan)?

Hẹn gặp lại anh em ở Bài học 28: Đọc hiểu Execution Plan (Query Plan Explanation) – Phân tích các Stage, Slot time consumed và phát hiện nút thắt cổ chai!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí