OLAP & Column-Oriented Storage — Khi phân tích dữ liệu cần tốc độ (DDIA)
Mở đầu
Ảnh: Negative Space — Pexels
Trong thực tế, database không chỉ dùng để xử lý giao dịch (vài row, vài giây). Còn một lớp workload khác — phân tích dữ liệu lớn — mà hầu hết backend engineer đều phải đụng mặt: report, dashboard, BI tools. Nếu OLTP (Online Transaction Processing) là "chạy từng giao dịch nhỏ, nhanh", thì OLAP (Online Analytical Processing) là "quét hàng triệu row, tính toán tổng hợp". Hai thế giới hoàn toàn khác nhau, và Column-Oriented Storage ra đời để giải quyết bài toán thứ hai.
Trong phần này của Chương 3 DDIA, Martin Kleppmann chỉ ra tại sao lưu dữ liệu theo cột (column-oriented) lại nhanh hơn rất nhiều so với row-oriented cho truy vấn phân tích — và những trade-off đi kèm.
OLTP vs OLAP — Hai con đường rẽ
Ảnh: Lukas Blazek — Pexels
Hầu hết ứng dụng đều bắt đầu với OLTP: insert, update, delete từng dòng một, index hỗ trợ tìm nhanh theo key. Nhưng khi business cần "doanh thu tháng trước là bao nhiêu?", "top 10 sản phẩm bán chạy?" — những câu hỏi này quét qua rất nhiều hàng, chỉ lấy vài cột. Row-oriented storage (PostgreSQL, MySQL, InnoDB) không được thiết kế cho việc này: nó đọc cả row dù bạn chỉ cần 3 cột.
Giải pháp kinh điển: tách riêng một data warehouse. Dữ liệu từ các OLTP database được ETL (Extract-Transform-Load) định kỳ vào data warehouse, nơi nó được tối ưu cho truy vấn phân tích. Các hệ thống phổ biến: Amazon Redshift, Google BigQuery, Snowflake, Apache Druid, ClickHouse.
Star Schema và Snowflake Schema — Cách tổ chức dữ liệu phân tích
Trong data warehouse, dữ liệu thường được tổ chức theo star schema (lược đồ hình sao):
- Fact table (bảng sự kiện): chứa các dòng dữ liệu giao dịch — mỗi dòng là một sự kiện (bán hàng, click, view), với các foreign key trỏ tới dimension tables.
- Dimension tables (bảng chiều): chứa thông tin mô tả — ngày tháng, sản phẩm, khách hàng, cửa hàng.
Snowflake schema là biến thể chuẩn hoá hơn: dimension tables được tách thành nhiều bảng con (ví dụ: "sản phẩm" → "danh mục" → "nhóm sản phẩm"). Star schema dễ dùng hơn cho truy vấn trực tiếp, snowflake schema tiết kiệm storage hơn.
Điểm mấu chốt: fact table có thể có hàng tỷ dòng, nhưng bạn chỉ cần quét 3-5 cột trong số 100+ cột. Đây là lúc column-oriented storage phát huy sức mạnh.
Column-Oriented Storage — Lưu theo cột, không theo hàng
Ảnh: Sergei Starostin — Pexels
Thay vì lưu toàn bộ row liên tiếp nhau trên disk (row-oriented), column-oriented storage lưu mỗi cột thành một file riêng, với các giá trị được sắp xếp theo cùng thứ tự hàng. Nếu fact table có 100 cột, bạn sẽ có 100 file — mỗi file chứa tất cả giá trị của cột đó.
Lợi ích cho truy vấn phân tích là rõ ràng:
- Giảm I/O khủng khiếp: Truy vấn SELECT SUM(price), COUNT(*) WHERE date BETWEEN '2025-01-01' AND '2025-06-30' chỉ cần đọc 2-3 cột (price, date) — không đọc 97 cột còn lại.
- Nén dữ liệu siêu hiệu quả: Các giá trị trong cùng một cột thường giống nhau (cùng kiểu dữ liệu, ít unique value). Kỹ thuật nén như bitmap encoding, run-length encoding (RLE) có thể giảm dung lượng xuống 10-20 lần.
- Cache locality tốt hơn: CPU cache chứa nhiều giá trị hữu ích hơn vì chúng cùng kiểu, cùng ý nghĩa.
Sort Order — Sắp xếp có chủ đích
Một tính năng thú vị của column store: bạn có thể sắp xếp các row theo một thứ tự nhất định (không chỉ mỗi cột riêng lẻ). Giống như index clustered trong InnoDB, nhưng áp dụng cho toàn bộ table. Điều này giúp:
- Tối ưu nén: Nếu sort theo date, các giá trị date giống nhau nằm cạnh nhau → RLE hiệu quả hơn.
- Tối ưu truy vấn: Nếu sort theo date, truy vấn theo khoảng thời gian chỉ cần scan một vùng nhỏ, không phải toàn bộ cột.
Thường bạn chỉ có thể có 1-2 sort orders (vì dữ liệu chỉ được sắp xếp một lần trên disk). Một số hệ thống (như ClickHouse) cho phép nhiều sort keys, hoặc dùng secondary indexes để hỗ trợ thêm.
Materialized Aggregates — Đánh đổi Storage lấy Tốc độ
Nếu query nào cũng là SELECT SUM/COUNT/AVG, tại sao không cache sẵn kết quả? Đó là ý tưởng của materialized views và data cubes (OLAP cubes):
- Materialized view: Một bảng ảo chứa kết quả aggregate được tính sẵn — giống cache nhưng persistent trên disk. Khi dữ liệu gốc thay đổi, materialized view có thể được refresh định kỳ.
- Data cube: Tổng hợp dữ liệu theo nhiều chiều (time, region, product) — bạn có thể "drill down" hoặc "roll up" mà không cần quét fact table.
Trade-off: materialized views làm tăng storage và phức tạp hoá write path (phải cập nhật cả view). Nhưng với workload read-heavy, đây là cách hiệu quả để giảm latency từ phút xuống giây.
Key Takeaways
- OLTP và OLAP có access pattern hoàn toàn khác nhau — không nên dùng chung database cho cả hai.
- Column-oriented storage tối ưu I/O cho truy vấn phân tích bằng cách chỉ đọc các cột cần thiết.
- Nén theo cột (bitmap encoding, RLE) có thể giảm dung lượng 10-20x, tăng tốc query đáng kể.
- Sort order có chủ đích và materialized aggregates là hai kỹ thuật mạnh để tối ưu OLAP workloads.
- Các hệ thống phổ biến hiện nay: ClickHouse (column store thuần), Apache Druid (time-series + column store), Google BigQuery / Snowflake (cloud-native column stores).
📋 Phụ lục thuật ngữ
| Thuật ngữ | Ý nghĩa |
|---|---|
| OLTP | Online Transaction Processing — xử lý giao dịch nhỏ, truy vấn theo key, write-heavy. |
| OLAP | Online Analytical Processing — truy vấn tổng hợp trên lượng lớn dữ liệu, read-heavy. |
| Data Warehouse | Kho dữ liệu riêng biệt, tối ưu cho phân tích, được ETL từ OLTP sources. |
| Star Schema | Lược đồ hình sao: một fact table trung tâm nối với nhiều dimension tables. |
| Column-Oriented Storage | Lưu dữ liệu theo cột thay vì theo hàng, tối ưu cho scan nhiều hàng nhưng ít cột. |
| Bitmap Encoding | Kỹ thuật nén cột: mỗi giá trị unique có 1 bitmap, bit 1/0 đánh dấu các hàng mang giá trị đó. |
| RLE (Run-Length Encoding) | Nén các giá trị giống nhau liên tiếp thành (value, count) pairs. |
| Materialized View | Kết quả aggregate được tính sẵn và lưu trên disk, dùng như cache cho query. |
| Data Cube | OLAP cube — tổng hợp dữ liệu đa chiều, hỗ trợ drill-down / roll-up. |
Kết
OLAP và column-oriented storage là một trong những chủ đề "người trong cuộc" — dev backend lâu năm có thể không đụng tới hằng ngày, nhưng một khi cần làm report hay dashboard, những kiến thức này cực kỳ giá trị. Nếu bạn đang chọn database cho một hệ thống phân tích, hãy nhìn vào ClickHouse (self-hosted, hiệu năng cao) hoặc BigQuery / Snowflake (managed, không lo scale). Còn nếu muốn hiểu sâu hơn, Chapter 3 của DDIA có toàn bộ chi tiết về storage engines và encoding.
Bài tiếp theo trong series DDIA sẽ nói về Encoding & Evolution — cách dữ liệu được serialize khi di chuyển giữa các service, và làm sao để thay đổi schema mà không crash production.