Data Modeling 2 — Mô hình chiều (Kimball): star & snowflake
Vì sao lại là "dimensional"?
Ở bài Nền tảng data modeling chúng ta đã tách biệt hai thế giới: mô hình giao dịch (OLTP, tối ưu để ghi từng bản ghi nhỏ, chuẩn hoá cao) và mô hình phân tích (OLAP, tối ưu để đọc — tổng hợp hàng triệu dòng). Bài này đi sâu vào trường phái thống trị thế giới phân tích suốt hơn ba thập kỷ: mô hình chiều (dimensional modeling) theo Ralph Kimball.
Vì sao dimensional lại phổ biến đến vậy? Ba lý do cốt lõi:
-
Dễ hiểu cho người nghiệp vụ. Một mô hình chiều tốt phản ánh đúng cách một nhà phân tích nghĩ về công việc: "doanh số theo sản phẩm, theo khu vực, theo tháng". Những từ nghiêng đó chính là các chiều (dimension). Người dùng không cần hiểu 3NF hay khoá ngoại phức tạp — họ nhìn thấy một cấu trúc gần như là ngôn ngữ tự nhiên.
-
Truy vấn nhanh và dự đoán được. Cấu trúc hình sao (star) tạo ra các mẫu join đơn giản, đồng nhất. Optimizer của kho dữ liệu (BigQuery, Snowflake, Redshift) nhận diện tốt mẫu này — có cả kỹ thuật star join optimization riêng.
-
Hợp với công cụ BI. Power BI, Looker, Tableau đều được thiết kế quanh giả định dữ liệu ở dạng chiều. Xem thêm BI-03 — Dimensional modeling cho BI và Power BI data model — mô hình star chính là "ngôn ngữ mẹ đẻ" của các công cụ này.
Quy ước trong bài: sandbox học tập dùng PostgreSQL. Mọi DDL mô hình chiều dưới đây là (minh hoạ) cho cấu trúc, không phải kịch bản thực thi hoàn chỉnh.
Fact và Dimension — hai loại bảng, hai vai trò
Toàn bộ mô hình Kimball xây trên đúng hai loại bảng.
Dimension (chiều) trả lời cho câu hỏi ai / cái gì / khi nào / ở đâu / như thế nào. Đó là ngữ cảnh mô tả một sự kiện. Bảng dimension thường:
- Rộng và nông: nhiều cột mô tả (tên, phân loại, cấp bậc, thuộc tính) nhưng tương đối ít dòng (vài nghìn khách hàng, vài trăm sản phẩm).
- Chứa các thuộc tính dạng text mà người dùng dùng để lọc, nhóm, gán nhãn trong báo cáo.
- Có một khoá thay thế (surrogate key) làm khoá chính.
Fact (sự kiện) trả lời cho câu hỏi bao nhiêu / mấy lần. Đó là một sự kiện kinh doanh đo lường được. Bảng fact thường:
- Hẹp và sâu: ít cột nhưng cực nhiều dòng (hàng triệu, hàng tỷ giao dịch).
- Chứa measures (số đo, additive facts như số tiền, số lượng) và một bó khoá ngoại trỏ tới các dimension.
- Là nơi tập trung khối lượng dữ liệu và cũng là nơi diễn ra các phép SUM/COUNT/AVG.
Ví dụ trực quan trong bán lẻ: một dòng fact "bán một lô 3 hộp sữa X với giá 90.000đ tại cửa hàng Hà Nội lúc 10h ngày 1/7". Số 3, số 90.000 là measure; sữa X, cửa hàng Hà Nội, ngày 1/7 là các khoá trỏ tới dimension sản phẩm, cửa hàng, ngày.
Mẹo phân biệt nhanh: nếu một cột được dùng để tính toán (cộng, đếm, trung bình) thì nó là measure trong fact; nếu được dùng để cắt lát / nhóm (group by, filter) thì nó thuộc dimension.
Grain — bước quan trọng nhất
Nếu chỉ được nhớ một điều từ Kimball, hãy nhớ grain (độ hạt). Grain là câu trả lời chính xác cho: "một dòng trong bảng fact đại diện cho cái gì?"
Ví dụ các grain khác nhau của cùng một quy trình bán hàng:
- Một dòng = một dòng chi tiết trên hoá đơn (một sản phẩm trên một hoá đơn) — grain rất mịn.
- Một dòng = một hoá đơn (đã gộp các sản phẩm).
- Một dòng = tổng doanh số một cửa hàng một ngày — grain thô, đã tổng hợp sẵn.
Tại sao grain quan trọng đến vậy?
-
Grain quyết định mọi thứ phía sau. Sau khi chốt grain, bạn mới biết dimension nào áp dụng được và measure nào hợp lệ. Chọn dimension trước khi chốt grain là công thức của mâu thuẫn.
-
Mọi dimension và measure phải nhất quán với grain. Nếu grain là "một dòng chi tiết hoá đơn" thì measure "số lượng bán" nằm đúng ở dòng đó. Nhưng "tổng giá trị hoá đơn" thì KHÔNG thuộc grain này — nó thuộc grain hoá đơn. Nhồi nó vào sẽ gây double-counting khi SUM.
-
Grain càng mịn càng tốt (nếu chịu nổi chi phí). Grain mịn nhất (atomic grain) cho phép trả lời tối đa số câu hỏi và dễ tổng hợp lên bất kỳ mức nào. Ngược lại, đã tổng hợp sớm thì mất chi tiết vĩnh viễn. Kimball khuyên: luôn xây bảng fact ở grain nguyên tử; các bảng tổng hợp (aggregate) chỉ là lớp tăng tốc bổ sung.
Nguyên tắc vàng: một bảng fact = một grain. Đừng trộn nhiều mức chi tiết vào cùng một bảng.
Star schema — trái tim của Kimball
Star schema là cách sắp xếp: một bảng fact ở trung tâm, các bảng dimension phẳng toả ra xung quanh như các cánh sao. Fact nối với mỗi dimension bằng một khoá.
Vì sao star được ưa chuộng?
- Ít join. Mọi câu hỏi phân tích chỉ cần join fact với vài dimension liên quan — luôn là join một cấp từ trung tâm ra cánh. Không có chuỗi join dài xuyên nhiều bảng.
- Dễ hiểu. Nhìn sơ đồ là biết ngay đo cái gì (fact ở giữa) và cắt lát theo gì (các cánh).
- Tối ưu cho engine phân tích. Kho cột (columnar) và optimizer nhận diện mẫu star; các dimension nhỏ dễ nạp vào bộ nhớ để làm hash join / broadcast join. Power BI thậm chí khuyến nghị mạnh mô hình star vì công cụ VertiPaq của nó nén và quét nhanh nhất trên cấu trúc này.
Một điểm tinh tế: dimension trong star được cố ý phi chuẩn hoá (denormalized). Ví dụ trong DIM_KHACH_HANG, ta để luôn tinh_thanh như một cột text, không tách ra bảng tỉnh riêng. Điều này đi ngược 3NF nhưng cố tình — đổi một chút dư thừa dữ liệu lấy sự đơn giản khi truy vấn.
Ví dụ DDL — star schema (minh hoạ)
Dưới đây là khai báo một star schema bán hàng, viết cho PostgreSQL nhưng để minh hoạ cấu trúc:
-- (minh hoạ)
-- Dimension: phi chuan hoa co y, moi dong la mot thuc the mo ta
CREATE TABLE dim_khach_hang (
khach_hang_sk BIGINT PRIMARY KEY, -- surrogate key
cif VARCHAR(20), -- natural/business key
ho_ten VARCHAR(200),
phan_khuc VARCHAR(50), -- Retail / Priority / SME
tinh_thanh VARCHAR(100) -- de luon o day (denormalized)
);
CREATE TABLE dim_ngay (
ngay_sk INT PRIMARY KEY, -- dang 20260701
ngay DATE NOT NULL,
thang INT,
quy INT,
nam INT,
thu_trong_tuan VARCHAR(15)
);
CREATE TABLE dim_san_pham (
san_pham_sk BIGINT PRIMARY KEY,
ma_sp VARCHAR(30),
ten_sp VARCHAR(200),
nhom_sp VARCHAR(80),
thuong_hieu VARCHAR(80)
);
-- Fact: hep va sau, khoa ngoai + measure
CREATE TABLE fact_ban_hang (
ban_hang_sk BIGINT PRIMARY KEY,
khach_hang_sk BIGINT REFERENCES dim_khach_hang,
san_pham_sk BIGINT REFERENCES dim_san_pham,
ngay_sk INT REFERENCES dim_ngay,
so_hoa_don VARCHAR(30), -- degenerate dimension
so_luong INT NOT NULL, -- measure (additive)
doanh_thu NUMERIC(18,2) NOT NULL, -- measure (additive)
chiet_khau NUMERIC(18,2) -- measure (additive)
);
Vài điểm đáng chú ý:
khach_hang_sklà surrogate key — một số nguyên vô nghĩa do kho dữ liệu tự sinh, tách khỏicif(khoá nghiệp vụ). Surrogate key giúp cách ly kho khỏi thay đổi ở nguồn và là điều kiện tiên quyết để làm SCD (theo dõi lịch sử thay đổi) — chi tiết ở Dimensions & SCD.so_hoa_donnằm ngay trong fact mà không có bảng dimension tương ứng — đây là degenerate dimension (chiều thoái hoá): một mã định danh giao dịch không có thuộc tính mô tả nào khác.dim_ngaygần như không bao giờ thiếu trong mọi mô hình — nó là dimension "role-playing" điển hình. Xem sâu về các loại fact và dimension đặc biệt ở Fact tables.
Snowflake schema — khi nào chấp nhận chuẩn hoá?
Snowflake schema là biến thể trong đó dimension được chuẩn hoá thành nhiều bảng con. Thay vì để nhom_sp và thuong_hieu như cột text trong dim_san_pham, ta tách chúng ra bảng riêng và nối bằng khoá:
Đánh đổi của snowflake:
| Tiêu chí | Star | Snowflake |
|---|---|---|
| Số bảng / join | Ít, phẳng | Nhiều, phân cấp |
| Dư thừa dữ liệu | Cao (chấp nhận) | Thấp (chuẩn hoá) |
| Dễ hiểu với người dùng | Rất dễ | Khó hơn |
| Tốc độ truy vấn | Nhanh, dự đoán được | Chậm hơn (nhiều join) |
| Tiết kiệm lưu trữ | Kém hơn | Tốt hơn |
Khi nào chấp nhận snowflake?
- Khi một dimension cực lớn và có phân cấp rõ ràng mà việc lặp lại text gây lãng phí đáng kể (hiếm với kho cột hiện đại vì nén rất tốt).
- Khi cần quản trị dữ liệu master tập trung cho một cấp phân cấp (ví dụ danh mục sản phẩm dùng chung cần cập nhật một chỗ).
- Khi công cụ hoặc quy ước tổ chức yêu cầu.
Thực tế ngày nay, với lưu trữ rẻ và engine cột mạnh, star gần như luôn thắng. Kimball bản thân khuyến nghị tránh snowflake trừ khi có lý do rõ ràng, vì nó hy sinh cái quý nhất của mô hình chiều: sự dễ hiểu và tốc độ.
Bus matrix & conformed dimensions — tích hợp toàn doanh nghiệp
Một star schema đơn lẻ giải quyết được một quy trình. Nhưng doanh nghiệp có hàng chục quy trình: bán hàng, tồn kho, thu nợ, huy động vốn... Làm sao để các mô hình rời rạc này ghép lại thành một bức tranh thống nhất mà không phải xây lại từ đầu?
Câu trả lời của Kimball là Enterprise Bus Architecture, với hai khái niệm trụ cột.
Conformed dimension (chiều đồng nhất)
Một dimension được gọi là conformed khi nó được dùng chung, nhất quán giữa nhiều bảng fact / data mart. "Nhất quán" ở đây rất chặt: các bản sao của dimension hoặc giống hệt nhau (cùng khoá, cùng thuộc tính, cùng giá trị), hoặc bản này là tập con hoàn hảo của bản kia. Mỗi thuộc tính có tên, định nghĩa và miền giá trị được thống nhất.
Sức mạnh của conformed dimension: nó cho phép drill-across — nối kết quả từ nhiều quy trình khác nhau. Nếu dim_khach_hang là conformed, ta có thể đặt cạnh nhau "doanh số bán" (từ fact bán hàng) và "dư nợ" (từ fact tín dụng) theo cùng một khách hàng, vì cả hai đều tham chiếu đúng một định nghĩa khách hàng. Không có conformed dimension, mỗi phòng ban tự định nghĩa "khách hàng" theo cách riêng và các con số không bao giờ khớp.
Enterprise bus matrix
Bus matrix là công cụ lập kế hoạch: một ma trận với hàng = quy trình kinh doanh (mỗi hàng thường thành một bảng fact) và cột = các dimension dùng chung. Ô được đánh dấu khi quy trình đó sử dụng dimension đó.
| Quy trình \ Dimension | Ngày | Khách hàng | Tài khoản | Sản phẩm | Kênh | Nhân viên |
|---|---|---|---|---|---|---|
| Giao dịch tài khoản | X | X | X | X | ||
| Giải ngân tín dụng | X | X | X | X | X | |
| Huy động tiền gửi | X | X | X | X | X | |
| Phí dịch vụ | X | X | X | X | X |
Nhìn vào ma trận, các cột được đánh dấu ở nhiều hàng chính là ứng viên conformed dimension — nơi cần đầu tư định nghĩa chuẩn một lần và tái sử dụng. Ma trận vừa là bản đồ kiến trúc chiến lược (nhìn từ trên xuống để đảm bảo dữ liệu tích hợp được toàn doanh nghiệp), vừa cho phép triển khai linh hoạt từng bước (xây từng quy trình một, bottom-up). Đây chính là cách Kimball cân bằng giữa tầm nhìn tổng thể và tốc độ giao hàng thực tế.
Quy trình thiết kế 4 bước của Kimball
Kimball chuẩn hoá việc thiết kế mọi bảng fact thành đúng bốn bước, theo thứ tự bắt buộc:
-
Chọn quy trình kinh doanh (select the business process). Là một hoạt động vận hành cốt lõi tạo ra sự kiện đo lường được: xử lý đơn hàng, giải ngân khoản vay, ghi nhận giao dịch. Bắt đầu từ quy trình có giá trị và dữ liệu sẵn sàng nhất, không phải từ báo cáo hay phòng ban.
-
Khai báo grain (declare the grain). Xác định chính xác một dòng fact đại diện cho cái gì. Nên chọn grain nguyên tử (thấp nhất có thể). Đây là bản lề của cả thiết kế.
-
Xác định dimension (identify the dimensions). Trả lời "sự kiện này được mô tả bởi những ngữ cảnh nào?" — đính kèm càng nhiều thuộc tính mô tả hữu ích càng tốt, ưu tiên tái dùng conformed dimension đã có.
-
Xác định fact / measure (identify the facts). Trả lời "quy trình này đo lường cái gì?" — thường là các số đo cộng dồn được (additive): số tiền, số lượng, số phí. Mỗi measure phải đúng ở grain đã khai báo.
Thứ tự này không thể đảo. Chọn dimension trước khi chốt grain, hay chọn measure không khớp grain, là hai lỗi kinh điển dẫn tới sai số khi tổng hợp.
Use case thực tế: star schema cho giao dịch ngân hàng
Áp dụng 4 bước cho bài toán quen thuộc: phân tích giao dịch tài khoản của một ngân hàng.
Bước 1 — Quy trình: Giao dịch trên tài khoản (nạp, rút, chuyển khoản, thanh toán). Đây là quy trình sinh sự kiện dày đặc và có giá trị phân tích cao (hành vi khách hàng, doanh thu phí, phát hiện gian lận).
Bước 2 — Grain: Một dòng fact = một giao dịch đơn lẻ (grain nguyên tử). Không gộp theo ngày, không gộp theo tài khoản. Với grain này ta có thể tổng hợp lên bất kỳ mức nào (theo giờ, theo kênh, theo phân khúc) sau này.
Bước 3 — Dimension:
dim_khach_hang(conformed — dùng chung với fact tín dụng, tiền gửi): CIF, họ tên, phân khúc, tỉnh thành.dim_tai_khoan: số tài khoản, loại tài khoản, loại tiền.dim_ngay+ có thểdim_gio(role-playing cho thời điểm giao dịch).dim_kenh: ATM, Internet Banking, quầy, Mobile.dim_loai_giao_dich: mã và mô tả loại giao dịch.
Bước 4 — Measure:
so_tien(số tiền giao dịch — additive).phi(phí thu — additive).so_luong_gd= 1 (đếm giao dịch — additive, tiện cho COUNT bằng SUM).
Kết quả là star schema đã vẽ ở sơ đồ mermaid đầu bài. Từ nó, một câu hỏi kiểu "tổng phí thu theo kênh, theo phân khúc khách hàng, trong quý 2" chỉ cần join fact_giao_dich với ba dimension và một GROUP BY — nhanh, rõ ràng, và cho ra con số nhất quán với mọi báo cáo khác cũng dùng cùng dimension đó.
So với Inmon và Data Vault — khi nào dùng gì?
Kimball không phải trường phái duy nhất. Ba cách tiếp cận chính:
-
Kimball (dimensional / bottom-up): xây các data mart hình sao quanh từng quy trình, tích hợp bằng conformed dimension. Ưu: nhanh có kết quả, dễ hiểu, hợp BI. Nhược: cần kỷ luật về conformed dimension để tránh phân mảnh. Dùng khi: mục tiêu chính là phân tích/BI, cần giao giá trị nhanh.
-
Inmon (3NF EDW / top-down): xây một kho dữ liệu doanh nghiệp chuẩn hoá 3NF làm nguồn sự thật trung tâm, rồi tạo các data mart chiều từ đó. Ưu: nhất quán và tích hợp chặt ở tầng lõi. Nhược: xây lâu, tốn kém trước khi có giá trị. Dùng khi: tổ chức lớn, ưu tiên tích hợp và quản trị dữ liệu doanh nghiệp lâu dài.
-
Data Vault: tách dữ liệu thành Hub (khoá nghiệp vụ), Link (quan hệ), Satellite (thuộc tính + lịch sử) ở tầng thô. Ưu: cực linh hoạt khi nguồn thay đổi, ghi lại toàn bộ lịch sử và audit tốt. Nhược: rất nhiều bảng, không dùng trực tiếp cho BI. Dùng khi: nhiều nguồn biến động, yêu cầu audit/tuân thủ cao — thường Data Vault ở tầng tích hợp còn Kimball ở tầng phục vụ. Xem Data Vault.
Trong thực tế hiện đại, ranh giới mờ đi: rất phổ biến kiến trúc dùng Data Vault (hoặc lớp thô/staging) để nạp và lưu lịch sử, rồi xây tầng star schema kiểu Kimball để phục vụ BI. Kimball vẫn là lớp mà người dùng cuối chạm vào.
Ghi nhớ
- Mô hình chiều tổ chức dữ liệu thành fact (đo lường được: measure + khoá) và dimension (ngữ cảnh: ai/gì/khi/đâu). Fact hẹp-sâu, dimension rộng-nông.
- Grain là bước quan trọng nhất: một dòng fact đại diện cho cái gì. Một bảng fact = một grain; ưu tiên grain nguyên tử; mọi dimension/measure phải khớp grain.
- Star schema (fact giữa, dimension phẳng xung quanh) được ưa chuộng vì ít join, dễ hiểu, tối ưu cho engine và công cụ BI. Snowflake chuẩn hoá dimension — chỉ chấp nhận khi có lý do rõ ràng.
- Conformed dimension (dùng chung nhất quán) + bus matrix (quy trình × dimension) là cách Kimball tích hợp toàn doanh nghiệp mà vẫn triển khai từng bước.
- Quy trình 4 bước (đúng thứ tự): chọn quy trình → khai báo grain → xác định dimension → xác định fact/measure.
- Surrogate key cho mọi dimension là nền tảng để làm SCD.
- Kimball hợp cho BI/phân tích và giao giá trị nhanh; Inmon thiên về EDW chuẩn hoá; Data Vault thiên về linh hoạt/audit — thường kết hợp Data Vault (tích hợp) + Kimball (phục vụ).
Đọc tiếp
Bài viết liên quan
CSV/JSON/Parquet/Avro, lưu trữ theo hàng vs cột, nén, và OLTP vs OLAP.
Data Engineering là gì, vai trò trong vòng đời dữ liệu, và bức tranh hệ sinh thái công cụ.
Vì sao xử lý phân tán, mô hình Spark (RDD/DataFrame), lazy evaluation, shuffle và tối ưu.
Đảm bảo chất lượng & minh bạch dữ liệu bằng dbt: data tests dựng sẵn (unique, not_null, relationships, accepted_values), singular test, unit test, và tài liệu tự sinh kèm lineage graph.