Data Modeling 5 — Data Vault 2.0
Vì sao lại có Data Vault?
Hãy hình dung một ngân hàng có mười hệ thống nguồn: core banking, thẻ, tín dụng, CRM, ứng dụng di động, tổng đài, hệ thống thu hồi nợ, cùng vài hệ thống mua ngoài sau các thương vụ M&A. Mỗi hệ thống có cách định danh khách hàng riêng, lịch nâng cấp riêng, và schema thay đổi liên tục theo yêu cầu nghiệp vụ. Đội kho dữ liệu (EDW) phải trả lời ba câu hỏi cùng lúc: (1) làm sao tích hợp cùng một khách hàng từ mười nguồn thành một bức tranh nhất quán; (2) làm sao lưu toàn bộ lịch sử thay đổi để phục vụ audit và truy vết — "giá trị này đến từ đâu, vào lúc nào"; và (3) làm sao nạp nhanh, song song, không để việc thêm một nguồn mới đập vỡ mô hình cũ.
Hai trường phái kinh điển đều gặp khó ở tầng tích hợp này. Mô hình 3NF/Inmon (chuẩn hoá cao) tích hợp tốt về mặt lý thuyết nhưng rất khó thay đổi: mỗi lần thêm nguồn hay đổi khoá nghiệp vụ là phải refactor các bảng đã chuẩn hoá chặt, kéo theo rủi ro và downtime. Mô hình Kimball (dimensional, star schema) thì tuyệt vời cho BI nhưng được thiết kế để phục vụ truy vấn, không phải để nuốt dữ liệu thô từ nhiều nguồn mâu thuẫn nhau; nhồi mọi nguồn thô trực tiếp vào dimension/fact sẽ khiến logic tích hợp và lịch sử (SCD) rối tung.
Data Vault (Dan Linstead sáng tạo, phiên bản 2.0 chuẩn hoá thêm hash key và phương pháp luận nạp) ra đời để làm tầng tích hợp doanh nghiệp: tách bạch khoá nghiệp vụ, quan hệ, và thuộc tính/lịch sử thành ba loại bảng riêng biệt. Nhờ tách bạch này, mỗi thay đổi ở nguồn chỉ ảnh hưởng cục bộ (thêm một satellite mới, thêm một link mới) thay vì phải sửa cấu trúc trung tâm. Data Vault không thay thế Kimball — nó nằm bên dưới, còn Kimball vẫn là tầng phục vụ BI phía trên.
Toàn bộ DDL trong bài là (minh hoạ) cho sandbox PostgreSQL, mục đích để bạn thấy cấu trúc chứ không nhằm chạy end-to-end trong một pipeline thật.
Ba thành phần cốt lõi: Hub, Link, Satellite
Triết lý của Data Vault gói gọn trong một câu: tách cái ít thay đổi ra khỏi cái thay đổi thường xuyên. Khoá nghiệp vụ (business key) gần như bất biến — số CIF của khách hàng, số tài khoản, mã sản phẩm hiếm khi đổi. Quan hệ giữa chúng thay đổi vừa phải. Còn thuộc tính mô tả (địa chỉ, hạn mức, phân khúc) thì đổi liên tục. Ba loại bảng ánh xạ đúng ba tốc độ thay đổi này.
Hub — danh sách khoá nghiệp vụ duy nhất
Hub chỉ chứa danh sách các business key duy nhất cho một khái niệm nghiệp vụ (khách hàng, tài khoản, sản phẩm). Hub không chứa thuộc tính mô tả. Cấu trúc chuẩn của một hub gồm:
- Hash key — khoá surrogate là hash (MD5/SHA-256) của business key.
- Business key — giá trị định danh gốc từ nghiệp vụ (vd
cif). - Load date (LDTS) — thời điểm bản ghi được nạp lần đầu vào vault.
- Record source (RSRC) — mã nguồn phát sinh, để truy vết xuất xứ.
Hub là "xương sống" ổn định của cả kho: chừng nào khách hàng còn tồn tại, hash key của họ không đổi, bất kể thuộc tính hay quan hệ biến động ra sao.
Link — quan hệ và giao dịch giữa các Hub
Link biểu diễn quan hệ hoặc giao dịch giữa hai hoặc nhiều hub (bản chất là quan hệ n–n). Một link chứa hash key riêng của nó cùng hash key của tất cả hub liên quan, kèm load date và record source. Ví dụ: quan hệ "khách hàng SỞ HỮU tài khoản" là một link nối hub_khach_hang với hub_tai_khoan. Một giao dịch chuyển khoản có thể là link nối tài khoản nguồn, tài khoản đích và ngày.
Điểm mạnh: Data Vault mặc định coi mọi quan hệ là nhiều–nhiều. Nhờ vậy, khi nghiệp vụ đổi từ "một khách hàng một tài khoản" sang "một khách hàng nhiều tài khoản đồng sở hữu", bạn không phải sửa cấu trúc — link vốn đã hỗ trợ điều đó.
Satellite — thuộc tính mô tả và lịch sử
Satellite chứa thuộc tính mô tả và toàn bộ lịch sử thay đổi theo thời gian, gắn với một hub hoặc một link. Satellite là append-only: mỗi lần thuộc tính đổi, một bản ghi mới được chèn thêm (giống hiệu ứng SCD Type 2), không ghi đè, nên lịch sử luôn được bảo toàn phục vụ audit.
Một hub có thể có nhiều satellite, tách theo:
- Nguồn dữ liệu: satellite khách hàng từ CRM tách khỏi satellite khách hàng từ core banking — mỗi nguồn nạp độc lập, không giẫm chân nhau.
- Tốc độ thay đổi: thuộc tính đổi nhanh (số dư, hạng thẻ) tách khỏi thuộc tính gần như tĩnh (ngày sinh, quốc tịch) để tối ưu lưu trữ.
Mỗi satellite dùng cột hashdiff — hash của tất cả cột mô tả — để phát hiện thay đổi nhanh: chỉ cần so sánh một cột hashdiff của bản ghi mới với bản ghi hiện hành, thay vì so sánh từng cột.
Hash key: chìa khoá của nạp song song
Vì sao Data Vault 2.0 dùng hash của business key thay cho surrogate key tuần tự (auto-increment)? Câu trả lời là khả năng nạp song song. Với surrogate tuần tự, muốn biết khoá của một khách hàng, bạn phải tra bảng hub trước (lookup) rồi mới nạp satellite/link — tạo ra phụ thuộc tuần tự giữa các bước nạp và điểm nghẽn tại bộ sinh số.
Với hash key, giá trị khoá được tính trực tiếp từ business key bằng hàm hash tất định (MD5/SHA-256). Nghĩa là:
- Có thể tính hash key của satellite/link cùng lúc với hub, không cần chờ lookup — cho phép nạp 100% song song giữa hub, link, satellite.
- Nhiều đội, nhiều tiến trình nạp độc lập mà không tranh chấp khoá.
- Trên kiến trúc phân tán (Spark, warehouse cột), hash tính được ở mọi node mà không cần điều phối tập trung.
Quy ước chuẩn hoá của Data Vault 2.0 còn bao gồm việc chuẩn hoá business key trước khi hash (trim, viết hoa, thứ tự cột cố định với khoá phức hợp) để cùng một khoá luôn cho cùng một hash ở mọi hệ thống.
DDL minh hoạ (PostgreSQL)
Dưới đây là bộ Hub + Link + Satellite tối giản cho khách hàng và tài khoản. (minh hoạ)
-- Hub: danh sách khoá nghiệp vụ duy nhất, KHÔNG thuộc tính mô tả
CREATE TABLE hub_khach_hang (
hk_khach_hang CHAR(32) NOT NULL, -- MD5(business key)
cif VARCHAR(20) NOT NULL, -- business key
load_date TIMESTAMP NOT NULL,
record_source VARCHAR(50) NOT NULL,
PRIMARY KEY (hk_khach_hang),
UNIQUE (cif)
);
CREATE TABLE hub_tai_khoan (
hk_tai_khoan CHAR(32) NOT NULL,
so_tai_khoan VARCHAR(30) NOT NULL,
load_date TIMESTAMP NOT NULL,
record_source VARCHAR(50) NOT NULL,
PRIMARY KEY (hk_tai_khoan),
UNIQUE (so_tai_khoan)
);
-- Link: quan hệ n-n giữa các hub (khách hàng SỞ HỮU tài khoản)
CREATE TABLE link_kh_tk (
hk_link CHAR(32) NOT NULL, -- MD5(cif || '||' || so_tai_khoan)
hk_khach_hang CHAR(32) NOT NULL,
hk_tai_khoan CHAR(32) NOT NULL,
load_date TIMESTAMP NOT NULL,
record_source VARCHAR(50) NOT NULL,
PRIMARY KEY (hk_link),
FOREIGN KEY (hk_khach_hang) REFERENCES hub_khach_hang(hk_khach_hang),
FOREIGN KEY (hk_tai_khoan) REFERENCES hub_tai_khoan(hk_tai_khoan)
);
-- Satellite: thuộc tính + lịch sử, gắn với hub, append-only, có hashdiff
CREATE TABLE sat_kh_crm (
hk_khach_hang CHAR(32) NOT NULL,
load_date TIMESTAMP NOT NULL,
hashdiff CHAR(32) NOT NULL, -- MD5 của toàn bộ cột mô tả
record_source VARCHAR(50) NOT NULL,
ho_ten VARCHAR(200),
dia_chi VARCHAR(500),
phan_khuc VARCHAR(50),
PRIMARY KEY (hk_khach_hang, load_date), -- lịch sử theo thời gian
FOREIGN KEY (hk_khach_hang) REFERENCES hub_khach_hang(hk_khach_hang)
);
Cách nạp một hub (chỉ chèn khoá chưa tồn tại) minh hoạ tinh thần idempotent:
INSERT INTO hub_khach_hang (hk_khach_hang, cif, load_date, record_source)
SELECT md5(upper(trim(s.cif))), s.cif, now(), 'CRM'
FROM stg_crm_khach_hang s
WHERE NOT EXISTS (
SELECT 1 FROM hub_khach_hang h
WHERE h.hk_khach_hang = md5(upper(trim(s.cif)))
);
Satellite chỉ chèn khi hashdiff khác bản ghi hiện hành — đó là cách bắt thay đổi:
INSERT INTO sat_kh_crm (hk_khach_hang, load_date, hashdiff, record_source,
ho_ten, dia_chi, phan_khuc)
SELECT md5(upper(trim(s.cif))), now(),
md5(coalesce(s.ho_ten,'')||'|'||coalesce(s.dia_chi,'')||'|'||coalesce(s.phan_khuc,'')),
'CRM', s.ho_ten, s.dia_chi, s.phan_khuc
FROM stg_crm_khach_hang s
LEFT JOIN LATERAL (
SELECT hashdiff FROM sat_kh_crm x
WHERE x.hk_khach_hang = md5(upper(trim(s.cif)))
ORDER BY x.load_date DESC LIMIT 1
) cur ON true
WHERE cur.hashdiff IS DISTINCT FROM
md5(coalesce(s.ho_ten,'')||'|'||coalesce(s.dia_chi,'')||'|'||coalesce(s.phan_khuc,''));
Raw Vault vs Business Vault
Data Vault chia tầng vault thành hai phần với vai trò rất khác nhau.
Raw Vault là nơi nạp thô từ nguồn, không áp business rule, chỉ tách và hash. Nguyên tắc vàng: raw vault phải là bản sao trung thực và bất biến của những gì nguồn gửi tới — kể cả dữ liệu "xấu". Đây chính là nền tảng của khả năng audit: bạn luôn có thể trả lời "hệ thống nguồn thực sự nói gì, vào ngày nào", vì raw vault không diễn giải lại dữ liệu. Nếu sau này phát hiện business rule sai, bạn sửa rule và nạp lại từ raw vault mà không mất dữ liệu gốc.
Business Vault là tầng dẫn xuất, áp business rule lên trên raw vault: chuẩn hoá giá trị, tính toán, hợp nhất bản ghi trùng, gắn nhãn nghiệp vụ. Business vault còn chứa các cấu trúc trợ giúp truy vấn:
- PIT (Point-in-Time) table: giải quyết vấn đề khó nhất khi query Data Vault — một hub có nhiều satellite với các mốc load date lệch nhau, muốn lấy "trạng thái tại thời điểm T" phải join phức tạp và so ngày. PIT thực hiện các join này sẵn trong lúc nạp (thường theo lịch đêm) và lưu kết quả, biến truy vấn thành tra khoá đơn giản.
- Bridge table: giải quyết độ phức tạp cấu trúc khi phải đi qua chuỗi nhiều link (khách hàng → tài khoản → giao dịch → sản phẩm). Bridge dựng sẵn đường đi giữa các hub qua nhiều link, giảm số join phía dưới.
Nói ngắn gọn: raw vault để đúng và truy vết được; business vault để dùng được.
Kiến trúc phân tầng: Data Vault và Kimball bổ sung nhau
Data Vault không đứng một mình mà là một mắt xích trong pipeline phân tầng:
Điểm mấu chốt: information mart — tầng phục vụ người dùng cuối — thường được dựng dưới dạng star schema Kimball. Nghĩa là Data Vault và Kimball bổ sung nhau, không loại trừ. Data Vault lo phần tích hợp và lịch sử ở giữa; Kimball lo phần trình bày dễ hiểu và truy vấn nhanh ở đầu ra. Người dùng BI thậm chí không cần biết bên dưới là Data Vault — họ chỉ thấy các star schema quen thuộc. Mart có thể được vật chất hoá hoàn toàn, hoặc dựng dạng view/dbt model từ business vault.
So sánh Kimball vs Data Vault vs 3NF (Inmon)
| Tiêu chí | 3NF / Inmon | Data Vault 2.0 | Kimball (star) |
|---|---|---|---|
| Mục đích chính | Tích hợp doanh nghiệp chuẩn hoá | Tầng tích hợp: scale, audit, đa nguồn | Phục vụ truy vấn / BI |
| Vị trí trong pipeline | Tầng EDW trung tâm | Tầng tích hợp giữa | Tầng mart / trình bày |
| Khả năng thay đổi | Khó (refactor chuẩn hoá) | Rất linh hoạt (thêm sat/link) | Trung bình (SCD, thêm dim) |
| Tích hợp đa nguồn thô | Khó, cần dọn trước | Rất mạnh (mỗi nguồn 1 satellite) | Yếu ở dữ liệu thô mâu thuẫn |
| Audit / lịch sử | Có nhưng thủ công | Bẩm sinh (append-only, LDTS, RSRC) | Qua SCD Type 2 |
| Nạp song song | Hạn chế | Rất tốt (hash key) | Trung bình |
| Độ phức tạp / số bảng | Trung bình | Cao (rất nhiều bảng) | Thấp, dễ hiểu |
| Trực tiếp cho BI | Không tối ưu | Không — cần mart | Có, tối ưu |
Điểm cần khắc cốt: sức mạnh của Data Vault (tích hợp, audit, scale) đi kèm cái giá là rất nhiều bảng và truy vấn phức tạp. Vì thế Data Vault luôn cần một tầng mart phía trên để dùng thực tế. Nó không phải mô hình để business analyst query trực tiếp.
Khi nào KHÔNG cần Data Vault
Data Vault là công cụ cho bài toán quy mô và độ phức tạp cao. Đừng dùng nó vì "nghe hiện đại". Nếu kho của bạn ít nguồn (một hai hệ thống), schema ổn định, yêu cầu audit vừa phải, thì Data Vault chỉ mang lại chi phí không tương xứng: gấp nhiều lần số bảng, mọi query phải join qua nhiều tầng, đội ngũ phải học một phương pháp luận mới. Trong trường hợp đó, Kimball trực tiếp đơn giản hơn nhiều — dựng thẳng star schema, dùng SCD cho lịch sử, xong.
Quy tắc thực dụng: chọn Data Vault khi bạn thực sự có ≥ nhiều nguồn, schema thay đổi liên tục, và yêu cầu truy vết/audit nghiêm ngặt (ngân hàng, bảo hiểm, viễn thông, y tế). Ngược lại, mặc định Kimball.
Tự động hoá: Data Vault sinh ra để generate
Một đặc điểm tuyệt vời của Data Vault: cấu trúc của nó cực kỳ lặp lại và có quy luật. Mọi hub trông giống nhau (hash key + business key + LDTS + RSRC), mọi satellite theo cùng một mẫu load bằng hashdiff, mọi link theo cùng một mẫu. Điều này khiến Data Vault trở thành ứng viên lý tưởng cho tự động hoá bằng metadata: bạn khai báo business key và ánh xạ cột, còn code DDL và ETL được sinh ra tự động.
Hệ sinh thái thực tế phổ biến là gắn Data Vault với dbt qua các package như AutomateDV (trước là dbtvault): bạn viết vài dòng cấu hình macro (hub, link, sat), dbt sinh ra toàn bộ SQL nạp chuẩn hoá, kèm test và tài liệu. Điều này giải quyết nỗi lo "quá nhiều bảng" — bạn không viết tay từng bảng, mà mô tả metadata rồi để công cụ generate. Ngoài dbt còn có các nền tảng chuyên dụng (WhereScape, VaultSpeed) đi theo cùng triết lý.
Use case thực tế: hợp nhất khách hàng từ nhiều hệ thống
Bài toán quen thuộc ở ngân hàng: cùng một khách hàng tồn tại trong core banking (định danh bằng CIF), CRM (định danh bằng email/số CMND), và hệ thống thẻ (định danh bằng mã khách hàng nội bộ). Các hệ thống này đổi schema theo lịch riêng, và pháp chế yêu cầu truy vết được mọi thay đổi thông tin khách hàng.
Cách Data Vault xử lý:
- Một hub khách hàng duy nhất — chọn CIF làm business key chuẩn (hoặc dùng một business key doanh nghiệp được ánh xạ). Hub này là điểm hội tụ của cả ba nguồn.
- Ba satellite riêng theo nguồn —
sat_kh_core,sat_kh_crm,sat_kh_the. Mỗi nguồn nạp độc lập, song song, không giẫm chân. Khi CRM đổi schema thêm cột, chỉ satellite CRM bị ảnh hưởng; core và thẻ nạp bình thường. - Toàn bộ lịch sử được giữ — mỗi lần một nguồn báo địa chỉ mới, một bản ghi satellite mới được chèn với load date và record source. Audit sau này chỉ cần đọc satellite tương ứng để biết "giá trị này từ CRM, ngày này".
- Link nối quan hệ —
link_kh_tknối khách hàng với tài khoản; nếu sau này thêm khái niệm "khách hàng thuộc chi nhánh nào", chỉ cần thêm một link mới, không đụng vào cái cũ. - Dựng mart Kimball để dùng — từ hub + các satellite, business vault áp rule hợp nhất (ưu tiên nguồn nào khi mâu thuẫn), rồi vật chất hoá thành
dim_khach_hang(star schema) với các thuộc tính đã hợp nhất và cờ SCD. BI query trên dim này, hoàn toàn không thấy độ phức tạp bên dưới.
Kết quả: đội EDW tích hợp thêm một nguồn mới chỉ bằng cách thêm satellite vào hub sẵn có — nhanh, an toàn, không refactor. Còn người dùng vẫn có star schema thân thiện. Đây chính là lý do Data Vault và Kimball đi cùng nhau trong các kho lớn.
Ghi nhớ
- Data Vault là tầng tích hợp, không phải tầng phục vụ BI. Nó giải bài toán đa nguồn + thay đổi liên tục + audit mà 3NF (khó đổi) và Kimball (yếu ở tích hợp thô) không giải tốt ở giữa.
- Ba thành phần: Hub = khoá nghiệp vụ duy nhất (không thuộc tính); Link = quan hệ n–n giữa hub; Satellite = thuộc tính + lịch sử (append-only, hashdiff). Chuẩn field: hash key, load date (LDTS), record source (RSRC).
- Hash key thay surrogate tuần tự để nạp 100% song song, không phụ thuộc lookup.
- Raw Vault = thô, bất biến, audit được; Business Vault = áp rule + PIT/Bridge để dễ query.
- Kiến trúc: staging → raw vault → business vault → information marts (Kimball star). Data Vault và Kimball bổ sung nhau, không loại trừ.
- Đừng dùng Data Vault cho kho nhỏ/ít nguồn — Kimball trực tiếp đơn giản hơn nhiều. Nhiều bảng + luôn cần mart là cái giá phải trả.
- Cấu trúc lặp lại → tự động hoá bằng metadata; thực tế hay gắn với dbt (AutomateDV) để generate.
Đọc tiếp: Dimensions & SCD để hiểu cách dựng lịch sử ở tầng mart, và Modern / One Big Table & Metrics để thấy hướng đi ngược lại — đơn giản hoá cho kho hiện đại.
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.