Phân vùng không chỉ giúp pruning. Khi bạn join hoặc gom trên bảng phân vùng, PostgreSQL có thêm hai tối ưu nâng cao: partition-wise join và partition-wise aggregate — xử lý theo từng cặp vùng tương ứng thay vì gộp cả bảng. Điều bất ngờ: cả hai tắt mặc định. Bài này đo thật chúng làm gì và vì sao mặc định tắt.
Ý tưởng: join theo từng cặp vùng
Nếu hai bảng phân vùng giống hệt nhau (cùng khóa phân vùng, cùng ranh giới vùng — gọi là co-partitioned), thì join theo khóa đó có một cách tối ưu: thay vì gộp toàn bộ hai bảng rồi join một lần, PostgreSQL join từng cặp vùng tương ứng (o_0 ⋈ c_0, o_1 ⋈ c_1, ...) rồi ghép kết quả.
SET enable_partitionwise_join = on; -- mặc định OFF
SET enable_partitionwise_aggregate = on; -- mặc định OFF
SELECT count(*) FROM o JOIN c ON o.k = c.k; -- k là khóa phân vùng của cả hai

Hình 1: Partition-wise join thay một Hash Join lớn (gộp cả hai bảng) bằng một Append của nhiều join nhỏ theo từng cặp vùng. Yêu cầu hai bảng co-partitioned. Cả hai tối ưu tắt mặc định vì tăng thời gian lập kế hoạch.
Đo thật: cấu trúc plan và lợi ích
Tôi dựng hai bảng o và c cùng phân vùng theo k thành 8 vùng, rồi join theo k:

Hình 2: OFF: một Hash Join gộp cả hai bảng. ON: Append của 8 Hash Join theo từng cặp vùng (250k dòng mỗi cặp). Với work_mem=1MB, partition-wise giảm số batch tràn đĩa từ 32 xuống 4 (hash table mỗi vùng nhỏ hơn). Partition-wise aggregate: 268 ms → 214 ms (~20% nhanh hơn).
- Cấu trúc plan thay đổi: OFF cho một
Hash Joinlớn (gộpAppend(o_0..o_7)rồi join với hash của cảc); ON cho mộtAppendcủa 8Hash Joinnhỏ, mỗi cái xử lý một cặp vùng (250k dòng). - Lợi ích bộ nhớ: với
work_mem=1MB(buộc hash tràn đĩa), partition-wise=OFF cần 32 batch (hash cả bảng lớn, tràn nhiều), ON chỉ 4 batch (hash table mỗi vùng nhỏ, tràn ít hơn). Đây là lợi ích thật khi bộ nhớ hạn chế. - Partition-wise aggregate:
GROUP BY k(khóa phân vùng) với OFF là mộtHashAggregatetoàn bộ (268 ms); ON làAppendcủa HashAggregate từng vùng (214 ms) — nhanh hơn ~20%.
Trung thực: trên lab đơn luồng đã cache này, lợi ích khiêm tốn (aggregate ~20%, join gần như hòa về thời gian dù giảm batch). Win lớn nhất của partition-wise là song song hóa — mỗi join/aggregate của một vùng chạy trên một worker riêng, cho tốc độ tăng gần tuyến tính theo số core khi tải đủ lớn. Điều đó cần đo trên tải thật với parallelism bật.
Vì sao tắt mặc định
Cả enable_partitionwise_join và enable_partitionwise_aggregate tắt mặc định vì chúng làm tăng thời gian lập kế hoạch: planner phải xét thêm phương án per-partition cho mỗi cặp vùng, và với bảng nhiều vùng, chi phí lập kế hoạch tăng đáng kể. PostgreSQL chọn mặc định an toàn (tắt) và để bạn bật khi đã xác định có lợi.
Đánh đổi cần cân nhắc
Chỉ hoạt động khi hai bảng co-partitioned. Partition-wise join yêu cầu hai bảng có cùng khóa phân vùng và cùng ranh giới vùng. Nếu chúng phân vùng khác nhau (khác số vùng, khác dải), PostgreSQL không dùng được và rơi về join thường. Thiết kế co-partitioning là quyết định phải làm từ đầu (ví dụ cùng phân vùng theo tenant_id).
Bật làm tăng thời gian lập kế hoạch — cân nhắc phạm vi. Vì mặc định tắt vì lý do này, đừng bật toàn cục vô tội vạ. Bật ở mức session/truy vấn cho các truy vấn analytics nặng trên bảng phân vùng lớn, nơi lợi ích thực thi (đặc biệt song song) vượt xa chi phí lập kế hoạch. Với OLTP truy vấn ngắn, chi phí lập kế hoạch thêm có thể không đáng.
Lợi ích thật đến từ parallelism và bộ nhớ, không phải luôn từ thời gian đơn luồng. Như đo ở trên, đơn luồng có thể gần như hòa. Đừng bật rồi kỳ vọng nhanh gấp bội ngay; hãy đo với parallelism bật, work_mem thực tế, và tải giống production. Lợi ích rõ nhất ở join/aggregate lớn trên nhiều vùng với nhiều core.
Ba ý mang về
- Partition-wise join/aggregate xử lý theo từng cặp vùng tương ứng thay vì gộp cả bảng: đo thật, plan đổi từ một Hash Join lớn thành Append của 8 join nhỏ (mỗi cặp vùng), yêu cầu hai bảng co-partitioned (cùng khóa và ranh giới vùng).
- Lợi ích là bộ nhớ nhỏ hơn và song song hóa: đo thật, partition-wise join giảm số batch tràn đĩa từ 32 xuống 4 (hash table mỗi vùng nhỏ hơn), partition-wise aggregate nhanh hơn ~20% — nhưng win lớn nhất là mỗi vùng một worker (cần parallelism và tải thật).
- Cả hai tắt mặc định vì tăng thời gian lập kế hoạch: bật
enable_partitionwise_join/enable_partitionwise_aggregateở mức session cho analytics nặng trên bảng phân vùng lớn, không bật toàn cục vô tội vạ — và đo với parallelism/work_mem thực tế.
Phần sau ta xét khía cạnh vận hành thực dụng của phân vùng theo thời gian: Phần sau mổ xẻ quản lý partition theo thời gian — tạo partition tương lai tự động, ATTACH/DETACH, và dọn dữ liệu cũ bằng DROP partition thay vì DELETE.