Bài 18: Tối Ưu Vật Lý – Partitioning Và Parallel Query
"Khi dữ liệu vượt 100GB, đã đến lúc chia để trị và huy động binh đoàn CPU!"
1. Vấn Đề: Query Trên Bảng 100GB Chậm Không Thể Chấp Nhận
Scenario:
Bảng orders
(100GB) chứa dữ liệu 10 năm (2014-2023) với cấu trúc:
order_id
(PK)customer_id
order_date
amount
Yêu cầu: Tính tổng doanh thu theo tháng năm 2023:
SELECT
EXTRACT(MONTH FROM order_date) AS month,
SUM(amount)
FROM orders
WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY month;
Kết quả: Thời gian thực thi ~120 giây, Execution Plan hiển thị Seq Scan toàn bộ bảng.
2. Phân Tích Execution Plan
Bước 1: Hiểu Cơ Chế Full Scan
Gather (cost=1,000,000.00..1,200,000.00 rows=12 width=8)
Workers Planned: 1
-> Parallel Seq Scan on orders (cost=0.00..1,000,000.00 rows=12 width=8)
Filter: (order_date >= '2023-01-01' AND order_date <= '2023-12-31')
Vấn Đề Chính:
Toàn bộ 100GB được quét dù chỉ cần dữ liệu 1 năm (10% tổng size).
Parallel Workers chỉ 1 → Không tận dụng đa CPU.
Không có index hỗ trợ
order_date
.
3. Giải Pháp: Kết Hợp Partitioning Và Parallel Query
Bước 1: Tạo Partitioned Table
-- Bảng master
CREATE TABLE orders (
order_id BIGSERIAL,
customer_id INT,
order_date DATE NOT NULL,
amount NUMERIC
) PARTITION BY RANGE (order_date);
-- Partition cho năm 2023
CREATE TABLE orders_2023_01 PARTITION OF orders
FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');
... (Tạo tương tự cho các tháng còn lại)
CREATE TABLE orders_2023_12 PARTITION OF orders
FOR VALUES FROM ('2023-12-01') TO ('2024-01-01');
Bước 2: Cấu Hình Parallel Query (PostgreSQL)
ALTER SYSTEM SET max_parallel_workers_per_gather = 4; -- Sử dụng 4 workers
ALTER SYSTEM SET work_mem = '256MB'; -- Tăng bộ nhớ cho sort
SELECT pg_reload_conf();
Bước 3: Thêm Index Trên Partition
CREATE INDEX idx_orders_2023_date ON orders_2023_01 (order_date);
... (Tạo index cho từng partition 2023)
4. Execution Plan Sau Khi Tối Ưu
Finalize GroupAggregate (cost=5000.00..6000.00 rows=12 width=8)
-> Gather Merge (cost=5000.00..5800.00 rows=48 width=8)
Workers Planned: 4
-> Partial GroupAggregate (cost=4000.00..4200.00 rows=12 width=8)
-> Parallel Index Scan on orders_2023_01
... (Tương tự cho các partition 2023 khác)
Index Cond: (order_date >= '2023-01-01' AND order_date <= '2023-12-31')
Kết Quả:
Chỉ quét 12 partitions năm 2023 (10GB) thay vì 100GB → Giảm 90% I/O.
4 workers xử lý song song → Tận dụng đa CPU.
Thời gian thực thi: Từ 120 giây → 8 giây (93% cải thiện).
5. Tổng Kết
Chỉ Số | Trước Khi Tối Ưu | Sau Khi Tối Ưu |
Dữ Liệu Quét | 100GB | 10GB |
Thời Gian Thực Thi | 120,000 ms | 8,000 ms |
Số Workers | 1 | 4 |
Phương Pháp Scan | Seq Scan | Index Scan |
Lý Do Hiệu Quả:
Partitioning chia dữ liệu thành các phần nhỏ → Giảm I/O và lock.
Parallel Query xử lý đồng thời → Tăng tốc độ tính toán.
6. Bài Tập Thực Hành
Dataset Mẫu:
CREATE TABLE sensor_logs (
log_id BIGSERIAL,
sensor_id INT,
log_time TIMESTAMP,
value FLOAT
) PARTITION BY RANGE (log_time);
Yêu Cầu:
Tạo partitions theo ngày cho tháng 1/2024.
Chạy query tính giá trị trung bình mỗi giờ trong ngày 2024-01-15.
So sánh hiệu suất khi dùng Parallel Query vs không.
Câu Hỏi:
- Tại sao không nên tạo quá nhiều partitions (ví dụ: theo giây)?
7. Mở Rộng & Thảo Luận
Khi Nào Dùng Partitioning vs Sharding?
Tiêu Chí | Partitioning | Sharding |
Phạm Vi | Trong 1 database | Nhiều database/server |
Độ Phức Tạp | Trung bình | Cao |
Use Case | Dữ liệu lớn nhưng ở 1 node | Dữ liệu cực lớn, cần scale ngang |
Chiến Lược Partitioning Hiệu Quả
Range Partitioning: Dữ liệu theo thời gian (ngày/tháng/năm).
List Partitioning: Phân chia theo category (ví dụ: vùng địa lý).
Hash Partitioning: Phân tán đều dữ liệu (phù hợp cho cân bằng tải).
Cảnh Báo Khi Dùng Partitioning
Overhead Quản Lý: Mỗi partition có index riêng → Tăng chi phí maintain.
Giới Hạn Số Partition: PostgreSQL hỗ trợ tối đa ~32,000 partitions.
Case Study: Parallel Query Trong MySQL 8.0
-- Kích hoạt parallel query cho bảng lớn
ALTER TABLE orders PARALLEL 4;
-- Query tự động sử dụng parallel execution
SELECT /*+ PARALLEL(orders, 4) */ ...
FROM orders
WHERE ...
Kết Luận
Partitioning và Parallel Query là vũ khí tối thượng để xử lý dữ liệu lớn. Trong ví dụ này, thời gian query giảm từ 2 phút xuống còn 8 giây - cải thiện 93%! Ở bài tiếp theo (Bài 19), chúng ta sẽ khám phá cách đọc hiểu Execution Plan dạng JSON và sử dụng các công cụ trực quan hóa mạnh mẽ.
👉 Bài Tập Về Nhà: Tạo partitioned table cho bảng sales
theo quý và đo hiệu suất khi aggregate dữ liệu với max_parallel_workers_per_gather = 8
!