OLTP vs OLAP — hai workload đối lập trên cùng dữ liệu
Vì sao một query phân tích 'SUM doanh thu theo tháng' làm sập database giao dịch? Phân biệt OLTP và OLAP qua pattern đọc/ghi, mô hình lưu trữ — agnostic.
TL;DR: Một hệ thống dữ liệu phục vụ hai loại công việc rất khác nhau. OLTP (online transaction processing) là các giao dịch nhỏ, nhiều, ghi/đọc vài dòng theo khoá — đặt hàng, cập nhật trạng thái task. OLAP (online analytical processing) là các truy vấn phân tích quét hàng triệu dòng để tổng hợp — "doanh thu theo tháng theo vùng". Chạy query OLAP nặng trên database OLTP đang phục vụ người dùng làm chậm cả hệ thống, nên thực tế người ta tách dữ liệu sang một kho phân tích riêng (data warehouse) với mô hình lưu trữ tối ưu cho đọc. Hiểu sự phân đôi này là nền tảng để thiết kế vòng đời dữ liệu.
Dashboard TaskFlow chạy mượt suốt nhiều tháng. Một sáng, team Business mở báo cáo mới: "tổng số giờ hoàn thành task theo từng phòng ban, theo từng tháng, trong 2 năm qua". Query này quét 18 triệu dòng trong bảng tasks, GROUP BY phòng ban và tháng. Ngay khi nó chạy, mọi người dùng đang thao tác trên TaskFlow thấy app đơ: tạo task mất 4 giây thay vì 40ms, có request timeout.
Cùng một database, cùng một bảng — nhưng một câu query đã kéo sập trải nghiệm của hàng nghìn người dùng. Vì sao? Vì bạn vừa bắt một hệ thống thiết kế cho giao dịch làm công việc phân tích. Bài này phân biệt hai loại workload đó, giải thích vì sao chúng xung khắc, và vì sao mọi hệ thống dữ liệu trưởng thành đều tách chúng ra.
1. Analogy — Quầy thu ngân và phòng kế toán
Một siêu thị có hai bộ phận làm việc trên cùng dữ liệu bán hàng, nhưng theo hai nhịp hoàn toàn khác:
- Quầy thu ngân xử lý từng giao dịch một: quét mã, trừ kho, in hoá đơn — mỗi lần chạm vài món hàng, cực nhanh, xảy ra liên tục cả nghìn lần mỗi giờ. Sai một giao dịch là khách hàng phàn nàn ngay.
- Phòng kế toán cuối tháng mới ngồi tổng hợp: doanh thu theo ngành hàng, so sánh quý này với quý trước, lãi gộp theo chi nhánh — đọc toàn bộ sổ sách, ít lần, nhưng mỗi lần rất nặng.
Bắt nhân viên thu ngân dừng quét hàng để tính tổng doanh thu cả năm thì hàng người xếp hàng sẽ kẹt cứng. Đó chính xác là điều xảy ra khi bạn chạy query OLAP trên database OLTP.
| Siêu thị | Hệ thống dữ liệu |
|---|---|
| Quầy thu ngân — giao dịch nhỏ, liên tục | OLTP — đọc/ghi vài dòng theo khoá, độ trễ thấp |
| Phòng kế toán — tổng hợp định kỳ | OLAP — quét nhiều dòng, tổng hợp, độ trễ cao chấp nhận được |
| Mỗi giao dịch chạm vài món | OLTP chạm vài dòng theo primary key/index |
| Báo cáo đọc cả sổ sách | OLAP quét cả bảng để aggregate |
| Hai bộ phận, hai nhịp | Hai workload, nên tách hạ tầng |
OLTP = thu ngân (nhiều giao dịch nhỏ, nhanh). OLAP = kế toán (ít báo cáo lớn, nặng). Cùng dữ liệu, hai nhịp làm việc xung khắc.
2. OLTP — workload giao dịch
OLTP (online transaction processing) là loại workload phục vụ hoạt động hằng ngày của ứng dụng. Đặc trưng: số lượng query rất lớn, mỗi query chạm ít dòng và được định vị bằng khoá (primary key hoặc index). Người dùng cuối kích hoạt chúng và mong phản hồi tức thì.
-- OLTP: doc 1 task theo khoa -- vai mili-giay
SELECT id, title, status, assignee_id
FROM tasks
WHERE id = 48217;
-- OLTP: ghi mot trang thai moi
UPDATE tasks SET status = 'done', completed_at = NOW()
WHERE id = 48217;
-- OLTP: them mot dong
INSERT INTO tasks (title, project_id, assignee_id, status)
VALUES ('Fix login bug', 12, 7, 'todo');
Yêu cầu cốt lõi của OLTP: độ trễ thấp và throughput cao cho hàng nghìn giao dịch đồng thời, cùng tính đúng đắn (ACID — xem Module 7). Mỗi giao dịch nhỏ nên cái giá phải tối ưu là số lượt, không phải khối lượng mỗi lượt.
3. OLAP — workload phân tích
OLAP (online analytical processing) phục vụ ra quyết định kinh doanh: tổng hợp, so sánh, tìm xu hướng. Đặc trưng ngược hẳn OLTP: số lượng query ít, nhưng mỗi query quét rất nhiều dòng rồi aggregate (SUM, COUNT, AVG, GROUP BY). Người chạy là analyst hoặc dashboard, chấp nhận chờ vài giây đến vài phút.
-- OLAP: tong hop tren hang trieu dong
SELECT
d.department_name,
DATE_TRUNC('month', t.completed_at) AS month,
COUNT(*) AS tasks_done,
SUM(t.effort_hours) AS total_hours
FROM tasks t
JOIN users u ON u.id = t.assignee_id
JOIN departments d ON d.id = u.department_id
WHERE t.completed_at >= '2024-01-01'
GROUP BY d.department_name, DATE_TRUNC('month', t.completed_at)
ORDER BY month;
Query này không quan tâm một dòng cụ thể — nó đọc toàn bộ task trong 2 năm, nhóm lại và tính tổng. Thứ cần tối ưu là thông lượng quét (đọc nhiều dòng nhanh nhất có thể), không phải độ trễ tra cứu một dòng.
"Online" chỉ việc hệ thống trả lời trực tiếp theo yêu cầu (interactive), phân biệt với xử lý theo lô (batch) chạy ngầm. OLTP online vì người dùng chờ từng giao dịch; OLAP "online" theo nghĩa analyst truy vấn tương tác chứ không phải đợi báo cáo in qua đêm. Thuật ngữ OLAP do Edgar F. Codd đặt năm 1993.
4. Cơ chế — vì sao hai workload xung khắc
Vấn đề không chỉ là "query nặng". Vấn đề là cách dữ liệu được sắp trên đĩa tối ưu cho loại này thì tệ cho loại kia.
Database OLTP truyền thống lưu dữ liệu theo dòng (row-oriented): tất cả cột của một dòng nằm cạnh nhau. Đọc/ghi một task (tất cả cột của nó) chỉ cần chạm một chỗ — hoàn hảo cho OLTP. Nhưng khi query OLAP chỉ cần 2 cột (department_id, effort_hours) trên 18 triệu dòng, engine vẫn phải đọc qua mọi cột của mọi dòng (title, description, timestamps...) vì chúng nằm xen kẽ trên đĩa — lãng phí phần lớn I/O.
Row-oriented (OLTP) — moi cot cua 1 dong nam canh nhau:
[id=1, title=..., effort=3, dept=A] [id=2, title=..., effort=5, dept=B] ...
-> doc 1 task: 1 lan cham (nhanh)
-> SUM(effort): phai doc ca title, description... cua moi dong (phi)
Đó là lý do hệ thống phân tích dùng lưu trữ theo cột (column-oriented) — gom tất cả giá trị của một cột lại với nhau, để query analytic chỉ đọc đúng cột cần. Cơ chế row-store vs column-store và vì sao nó đổi mọi thứ được mổ riêng ở bài kế tiếp.
Thêm một xung khắc ở tầng tài nguyên: query OLAP quét bảng lớn chiếm hết bộ nhớ cache, I/O và CPU, đẩy các giao dịch OLTP nhỏ vào hàng đợi. Hai workload tranh nhau cùng một máy — đó là gốc rễ vì sao TaskFlow đơ ở đầu bài.
5. Lời giải — tách thành hai hệ thống
Vì hai workload xung khắc cả về mô hình lưu trữ lẫn tài nguyên, giải pháp chuẩn là tách: giữ database OLTP cho ứng dụng, và sao chép dữ liệu sang một data warehouse riêng tối ưu cho OLAP. Một pipeline định kỳ (ETL/ELT — xem bài 04) chuyển dữ liệu từ nguồn OLTP sang warehouse.
flowchart LR
subgraph OLTP["He thong OLTP (ung dung)"]
APP["App TaskFlow"] --> DB[("Database giao dich<br/>row-oriented")]
end
DB -->|"ETL / ELT dinh ky"| WH[("Data warehouse<br/>column-oriented")]
subgraph OLAP["He thong OLAP (phan tich)"]
WH --> BI["Dashboard / BI<br/>analyst query"]
endSau khi tách: query "doanh thu theo tháng" chạy trên warehouse, không đụng tới database đang phục vụ người dùng. TaskFlow không còn đơ. Đổi lại, dữ liệu trong warehouse trễ so với thực tế (cập nhật theo chu kỳ ETL — vài phút đến hằng ngày), nên OLAP chấp nhận đọc dữ liệu hơi cũ để đổi lấy không ảnh hưởng production.
6. Các thao tác OLAP kinh điển
Khi dữ liệu đã ở warehouse, analyst khám phá nó qua vài thao tác chuẩn, thường hình dung dữ liệu như một "khối" (cube) nhiều chiều:
| Thao tác | Ý nghĩa | Ví dụ TaskFlow |
|---|---|---|
| Roll-up (consolidation) | Gộp lên mức tổng quát hơn | Từ giờ-theo-ngày lên giờ-theo-quý |
| Drill-down | Đi sâu vào chi tiết | Từ tổng theo phòng ban xuống từng nhân viên |
| Slice | Cố định một chiều, lấy một lát | Chỉ xem quý 1 |
| Dice | Lọc nhiều chiều cùng lúc | Quý 1, phòng Engineering, task ưu tiên cao |
Bốn thao tác này đều quy về GROUP BY ở các mức khác nhau cộng với WHERE để lọc — kỹ thuật bạn đã học ở Module 3. Điểm khác là chúng chạy trên kho phân tích, trên khối lượng lớn.
7. Pitfall — chạy analytics trên database production
Cám dỗ lớn nhất khi hệ thống còn nhỏ: "cứ chạy báo cáo thẳng trên database chính cho tiện". Ổn khi dữ liệu vài chục nghìn dòng. Nhưng khi bảng lớn lên, một query aggregate quét toàn bảng sẽ:
- Chiếm I/O và cache, làm chậm mọi giao dịch OLTP đang chạy.
- Giữ lock/snapshot lâu, tăng áp lực lên cơ chế quản lý phiên bản dòng (xem Module 7).
- Khó tối ưu vì schema chuẩn hoá cho OLTP (nhiều bảng nhỏ, nhiều JOIN) không hợp cho quét lớn.
-- WRONG: chay thang tren DB production, gio cao diem
SELECT department_id, SUM(effort_hours)
FROM tasks
GROUP BY department_id; -- quet 18M dong, dong bang trai nghiem user
-- DUNG (huong tiep can):
-- 1. Chay tren read replica / data warehouse, KHONG phai primary
-- 2. Hoac materialized view cap nhat dinh ky
-- 3. Hoac ETL sang warehouse column-oriented
Quy tắc: khi báo cáo bắt đầu làm chậm app, đó là tín hiệu phải tách OLAP ra khỏi OLTP — đừng cố "tối ưu thêm index" trên database giao dịch.
8. 📚 Deep Dive
- Designing Data-Intensive Applications (Kleppmann) — Chương 3 "Storage and Retrieval", mục "Transaction Processing or Analytics?" — nguồn nền tảng cho sự phân đôi OLTP/OLAP và lưu trữ theo cột. Đọc trước khi sang bài row vs column store.
- Wikipedia — Online analytical processing — lịch sử thuật ngữ (Codd 1993) và các thao tác roll-up/drill-down/slice/dice.
- Wikipedia — Online transaction processing — đặc trưng workload giao dịch.
Ghi chú: DDIA Chương 3 là nguồn chuẩn, agnostic (không gắn engine) — giải thích vì sao mô hình lưu trữ quyết định loại workload nào chạy nhanh. Wikipedia cho định nghĩa và lịch sử thuật ngữ chính xác.
9. Liên hệ các bài khác
- Bài 02 — Row store vs column store: cơ chế lưu trữ giải thích vì sao OLTP và OLAP cần mô hình đĩa khác nhau — đọc ngay sau bài này.
- Bài 03 — Dimensional modeling & star schema: warehouse OLAP không chuẩn hoá như OLTP mà dùng lược đồ chiều để tối ưu đọc.
- Module 3 — GROUP BY & HAVING: nền tảng aggregate mà mọi thao tác OLAP dựa trên.
- Module 7 — Isolation levels: vì sao query phân tích dài giữ snapshot lâu gây áp lực lên DB giao dịch.
10. Tóm tắt
- OLTP = nhiều giao dịch nhỏ, đọc/ghi vài dòng theo khoá, độ trễ thấp — phục vụ ứng dụng.
- OLAP = ít query nhưng mỗi query quét nhiều dòng để tổng hợp — phục vụ phân tích, chấp nhận độ trễ cao hơn.
- Hai workload xung khắc vì mô hình lưu trữ (row vs column) và vì tranh tài nguyên trên cùng một máy.
- Lời giải chuẩn: tách dữ liệu sang data warehouse riêng, đồng bộ qua ETL/ELT; đổi lại dữ liệu phân tích trễ một chút.
- Thao tác OLAP kinh điển (roll-up, drill-down, slice, dice) đều quy về
GROUP BY+WHEREở các mức khác nhau. - Pitfall: chạy aggregate lớn thẳng trên DB production làm chậm toàn bộ giao dịch — tín hiệu cần tách OLAP.
11. Tự kiểm tra
Q1Cùng một database, cùng một bảng — vì sao một query phân tích 'SUM theo tháng' lại làm chậm cả các giao dịch nhỏ của người dùng?▸
Hai lý do. Thứ nhất, tranh tài nguyên: query phân tích quét hàng triệu dòng, chiếm hết bộ nhớ cache, băng thông I/O và CPU, đẩy các giao dịch OLTP nhỏ vào hàng đợi.
Thứ hai, mô hình lưu trữ không hợp: database giao dịch lưu theo dòng (row-oriented), nên dù query chỉ cần 2 cột, engine vẫn phải đọc qua mọi cột của mọi dòng — lãng phí phần lớn I/O. Kết quả: một query nặng kéo tụt độ trễ của hàng nghìn giao dịch nhẹ.
Q2Phân biệt OLTP và OLAP qua ba tiêu chí: số lượng query, số dòng mỗi query chạm, và thứ cần tối ưu.▸
- Số lượng query: OLTP rất nhiều (nghìn/giây); OLAP ít.
- Số dòng mỗi query: OLTP chạm vài dòng theo khoá; OLAP quét hàng nghìn đến hàng triệu dòng.
- Tối ưu cho: OLTP tối ưu độ trễ thấp + throughput giao dịch; OLAP tối ưu thông lượng quét (đọc nhiều dòng nhanh), chấp nhận độ trễ cao hơn.
Q3Vì sao tách dữ liệu sang data warehouse lại giải quyết được xung khắc, và cái giá phải trả là gì?▸
Tách giúp query phân tích chạy trên một hệ thống riêng (warehouse, thường column-oriented, tối ưu cho quét lớn), không đụng tới database đang phục vụ người dùng — nên giao dịch OLTP không còn bị tranh tài nguyên.
Cái giá: dữ liệu trong warehouse được đồng bộ định kỳ qua ETL/ELT (vài phút đến hằng ngày), nên nó trễ so với thực tế. OLAP chấp nhận đọc dữ liệu hơi cũ để đổi lấy việc không ảnh hưởng production — một đánh đổi hợp lý vì báo cáo phân tích hiếm khi cần dữ liệu thời gian thực tuyệt đối.
Q4Một startup nhỏ chạy báo cáo thẳng trên database chính và thấy vẫn nhanh. Khi nào cách này bắt đầu thành vấn đề, và dấu hiệu là gì?▸
Khi dữ liệu còn nhỏ (vài chục nghìn dòng), quét toàn bảng vẫn nhanh nên chạy thẳng trên DB chính là chấp nhận được — chưa cần hạ tầng OLAP riêng (YAGNI).
Cách này thành vấn đề khi bảng lớn lên: query aggregate quét toàn bảng bắt đầu chiếm I/O/cache và làm chậm các giao dịch OLTP. Dấu hiệu: thời gian phản hồi của app tăng vọt mỗi khi báo cáo chạy; timeout giờ cao điểm; giao dịch nhỏ bỗng chậm. Đó là lúc tách OLAP (read replica, materialized view, hoặc warehouse) thay vì cố thêm index trên DB giao dịch.
Q5Thao tác 'drill-down' và 'roll-up' trong OLAP thực chất ánh xạ sang cấu trúc SQL nào bạn đã học?▸
Cả hai đều quy về GROUP BY ở các mức gộp khác nhau. Roll-up là gộp lên mức tổng quát hơn (ví dụ từ GROUP BY ngày lên GROUP BY quý) — ít nhóm hơn, tổng quát hơn. Drill-down ngược lại, đi xuống mức chi tiết hơn (từ phòng ban xuống từng nhân viên) — nhiều nhóm hơn.
Slice và dice thì ánh xạ sang WHERE: slice cố định một chiều (một giá trị), dice lọc nhiều chiều cùng lúc. Nói cách khác, toàn bộ "khối OLAP" là cách hình dung trực quan của GROUP BY + WHERE trên dữ liệu nhiều chiều.
Bài tiếp theo: Row store vs column store — vì sao OLAP cần lưu theo cột
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên