# The Data Warehouse Toolkit: cuốn sách của Kimball giúp FDE giữ dashboard không tự đổi số liệu quá khứ

> Số liệu quý trước tự đổi dù không ai sửa một dòng code: thủ phạm thường là một quyết định modeling mà Ralph Kimball và Kimball Group đã gọi tên rõ ràng.

Bản gốc: https://fdetimes.net/vi/sach-khoa-hoc/sach-the-data-warehouse-toolkit-kimball/

Thử hình dung sáng thứ Hai, giám đốc kinh doanh của khách hàng mở dashboard và thấy doanh số miền Bắc của quý một đã giảm so với tuần trước. Không ai sửa pipeline, không ai xoá đơn hàng. Chỉ có một khách hàng lớn vừa chuyển trụ sở vào miền Nam, và hệ thống đã lặng lẽ viết lại quá khứ.

Nếu bạn là FDE phụ trách phần dữ liệu trong tình huống giả định đó, bạn sẽ là người phải giải thích.

Đó cũng là lý do *The Data Warehouse Toolkit, 3rd Edition*, cùng bộ trang kỹ thuật dimensional modeling mà Kimball Group công bố, vẫn đáng đọc: chúng gọi đúng tên cơ chế khiến số liệu cũ tự đổi, và chỉ cách thiết kế để chuyện đó chỉ xảy ra khi bạn chủ động muốn.

## Sách từ 2013 vẫn là ngôn ngữ của stack hôm nay

Ralph Kimball và Margy Ross cùng viết phiên bản thứ ba của cuốn hướng dẫn kinh điển về dimensional modeling mà Kimball khởi xướng, do Wiley xuất bản năm 2013.

Cuốn sách ra đời đã lâu, vậy mà tài liệu của dbt vẫn mô tả snapshots là cách hiện thực SCD Type 2 trên các bảng nguồn có thể thay đổi. Type 2 là khái niệm của Kimball, còn dbt snapshots là một cách hiện thực ý tưởng đó trong code.

Vì thế đọc Kimball giúp bạn hiểu snapshots giải quyết vấn đề gì, chứ không chỉ biết cách cấu hình nó. Kỹ năng FDE mà bộ tài liệu này rèn là biến câu hỏi nghiệp vụ mơ hồ thành một thiết kế dữ liệu có thể kiểm chứng, và có ba ý đáng mang theo đến bất kỳ dự án nào.

## Chưa chốt grain thì chưa được vẽ bảng

Trang kỹ thuật của Kimball Group định nghĩa grain là thứ xác định chính xác một dòng của bảng fact đại diện cho điều gì, và đây là quyết định đầu tiên phải chốt. Nghe đơn giản, nhưng nhiều cuộc cãi nhau về số liệu có thể truy ngược về đây.

Ví dụ, "mỗi dòng là một đơn hàng" và "mỗi dòng là một sản phẩm trong đơn hàng" cho ra hai con số "số đơn" khác nhau nếu ai đó đếm dòng. Một đơn ba sản phẩm sẽ bị đếm ba lần ở grain thứ hai.

**Điểm mấu chốt:** Dashboard đáng tin bắt đầu từ việc biết một dòng dữ liệu đại diện cho điều gì.

Việc đầu tiên tại khách hàng vì thế không phải mở SQL mà là viết grain thành một câu bằng ngôn ngữ nghiệp vụ và để người phụ trách bên khách hàng xác nhận.

## Ghi đè là một quyết định, không phải mặc định

Quay lại sự cố sáng thứ Hai. Với SCD Type 1, giá trị cũ trong dòng dimension bị thay bằng giá trị mới, và trang kỹ thuật của Kimball Group viết thẳng rằng kỹ thuật này phá huỷ lịch sử. Trang này còn cảnh báo phải tính lại các aggregate fact table và OLAP cube bị ảnh hưởng.

Hãy chạy thử trong đầu câu truy vấn mà dashboard kia dùng:

```sql
SELECT c.region, SUM(f.amount) AS doanh_so
FROM fact_orders f
JOIN dim_customer c ON f.customer_key = c.customer_key
WHERE f.order_date BETWEEN '2025-01-01' AND '2025-03-31'
GROUP BY c.region;
```

Giả sử tuần trước miền Bắc ra 1.000, trong đó 300 đến từ khách KH-07. Sau một lệnh `UPDATE dim_customer SET region = 'Miền Nam'` kiểu Type 1, câu truy vấn y hệt sẽ trả miền Bắc 700 và đẩy 300 sang miền Nam. Nếu bảng aggregate theo vùng chưa được tính lại, nó vẫn báo 1.000, và hai dashboard bắt đầu cãi nhau.

Type 2 xử lý khác: thêm một dòng mới vào dimension với giá trị đã cập nhật, gán một surrogate key mới, và key đó được dùng làm foreign key trong các fact table. Kimball Group khuyến nghị tối thiểu ba cột bổ sung: ngày hiệu lực, ngày hết hiệu lực và cờ dòng hiện hành. Bảng dimension khách hàng trong ví dụ sẽ trông thế này:

| customer_key | customer_id | region | ngày hiệu lực | ngày hết hiệu lực | hiện hành |
|---|---|---|---|---|---|
| 101 | KH-07 | Miền Bắc | 2024-01-01 | 2025-06-30 | N |
| 245 | KH-07 | Miền Nam | 2025-07-01 | 9999-12-31 | Y |

Chạy lại đúng câu SQL trên, đơn hàng quý một vẫn join vào key 101 nên miền Bắc vẫn là 1.000, còn đơn từ tháng bảy trỏ vào key 245.

Trong một bài viết năm 2008, Kimball lấy chính mình làm ví dụ: Type 2 đòi hỏi phát hành một bản ghi nhân viên mới cho Ralph Kimball có hiệu lực từ ngày 18/7/2008, thay vì sửa bản ghi cũ.

Không phải cột nào cũng cần Type 2. Sửa lỗi chính tả tên khách hàng thì ghi đè là hợp lý. Việc của bạn là hỏi khách hàng, với từng thuộc tính, rằng báo cáo quá khứ nên phản ánh giá trị lúc đó hay giá trị bây giờ.

## Định nghĩa một lần, dùng ở mọi nơi

Khi phòng sales và phòng tài chính mỗi bên có một bảng "khách hàng" riêng, hai dashboard rất khó khớp nhau. Kimball Group gọi lời giải là conformed dimension: định nghĩa một lần cùng bên quản trị dữ liệu của doanh nghiệp rồi tái dùng giữa các fact table, vừa giữ số liệu nhất quán vừa giảm chi phí phát triển về sau.

Điều kiện để hai dimension được coi là conformed khá cụ thể: các thuộc tính phải giống tên cột và giống miền giá trị. "Miền Bắc" ở một bảng và "MB" ở bảng kia là đủ để phá vỡ điều đó.

## Đọc theo vấn đề, không đọc như tiểu thuyết

Một lộ trình nên thử: mở trang Dimensional Modeling Techniques của Kimball Group, đọc lần lượt các mục Grain, Type 1, Type 2 rồi Conformed Dimensions, sau đó dùng cuốn sách để đào sâu từng chủ đề khi gặp tình huống thật. Cuối cùng, mở tài liệu dbt snapshots để nối lý thuyết với code.

Bộ tài liệu này phù hợp nhất với developer đã viết SQL thành thạo nhưng chưa từng chịu trách nhiệm cho một con số mà ban giám đốc dùng để ra quyết định.

Trên CV, một dòng kiểu "chuyển dimension khách hàng sang SCD Type 2 bằng dbt snapshots để báo cáo lịch sử không đổi khi khách đổi khu vực" có sức nặng hơn nhiều so với "thành thạo SQL".

Khách hàng hiếm khi hỏi bạn về Type 1 hay Type 2. Họ chỉ hỏi vì sao con số hôm qua khác hôm nay, và FDE nào trả lời được câu đó trong năm phút sẽ được tin ở mọi câu hỏi tiếp theo.

**Thử ngay tuần này:**

- Chọn một bảng fact trong dự án bạn đang làm, viết grain của nó thành một câu bắt đầu bằng 'Mỗi dòng là…' rồi gửi cho người nghiệp vụ xác nhận.
- Liệt kê các thuộc tính trong một bảng dimension khách hàng, đánh dấu cột nào đang bị ghi đè (Type 1) mà báo cáo lịch sử lại cần giá trị cũ.
- Dựng một dbt snapshot cho một bảng nguồn nhỏ, đổi thử một giá trị và kiểm tra dòng mới cùng các cột hiệu lực được sinh ra.

## Nguồn

- [The Data Warehouse Toolkit, 3rd Edition (Kimball Group)](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/books/data-warehouse-dw-toolkit/)

- [Grain | Kimball Dimensional Modeling Techniques](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/grain/)

- [Type 1: Overwrite | Kimball Dimensional Modeling Techniques](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/type-1/)

- [Type 2: Add New Row | Kimball Dimensional Modeling Techniques](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/type-2/)

- [Conformed Dimensions | Kimball Dimensional Modeling Techniques](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/conformed-dimension/)

- [Slowly Changing Dimensions, Part 2](https://www.kimballgroup.com/2008/09/slowly-changing-dimensions-part-2/)

- [Add snapshots to your DAG | dbt Developer Hub](https://docs.getdbt.com/docs/build/snapshots)
