Hướng Dẫn Sử Dụng Phân Vùng Bảng PostgreSQL - Nạp Tiền Nohu71

| Mar 8, 2025 min read

Ngày 21 tháng 10 năm 2023 - Công Nghệ Máy Tính

Phân vùng bảng là kỹ thuật chia một bảng lớn về mặt logic thành nhiều phần nhỏ hơn về mặt vật lý. Việc sử dụng phân vùng bảng có thể cải thiện hiệu suất và tối ưu hóa lưu trữ. PostgreSQL hỗ trợ cơ bản cho tính năng phân vùng bảng. Bài viết này sẽ dựa trên tài liệu chính thức của PostgreSQL 16 để giải thích vì sao cần sử dụng phân vùng bảng và cách thực hiện cụ thể.

Tại Sao Nên Sử Dụng Phân Vùng Bảng?

Việc áp dụng phân vùng bảng mang lại nhiều lợi ích đáng kể:

  • Đối với các trường hợp phân phối dữ liệu đặc biệt (ví dụ: hàng được truy cập thường xuyên nằm trong một hoặc vài phân vùng nhất định), phân vùng bảng có thể tăng hiệu suất đáng kể.
  • Khi truy vấn hoặc cập nhật tập trung vào phần lớn dữ liệu của một phân vùng duy nhất, quét tuần tự phân vùng đó sẽ hiệu quả hơn so với việc sử dụng chỉ mục (sử dụng chỉ mục yêu cầu truy cập ngẫu nhiên vào toàn bộ bảng).
  • Nếu thiết kế phân vùng phù hợp, có thể thêm hoặc xóa phân vùng để thực hiện tải hàng loạt và xóa hàng loạt. Lệnh DROP TABLE hoặc ALTER TABLE DETACH PARTITION để xóa một phân vùng đơn lẻ nhanh hơn nhiều so với thao tác hàng loạt, đồng thời hoàn toàn tránh được chi phí VACUUM từ lệnh DELETE.
  • Dữ liệu ít được sử dụng có thể được di chuyển sang phương tiện lưu trữ chậm hơn nhưng rẻ hơn nhiều.

Khi Nào Nên Sử Dụng Phân Vùng Bảng?

Theo khuyến nghị chính thức, khi kích thước bảng vượt quá dung lượng bộ nhớ vật lý của máy chủ cơ sở dữ liệu (bộ nhớ, không phải ổ cứng), việc phân vùng sẽ mang lại lợi ích.

Các Phương Thức Phân Vùng Trong PostgreSQL

  • Phân vùng theo khoảng: Sử dụng cột khóa chính hoặc tổ hợp các cột để chia bảng thành các đoạn khoảng liên tiếp mà không trùng lặp. Ví dụ, có thể sử dụng cột ngày hoặc ID số để phân vùng, và khoảng sau khi phân vùng nên giữ nguyên tắc đóng trái mở phải như [1, 10), [10, 20),....

  • Phân vùng theo danh sách: Liệt kê rõ ràng các giá trị khóa thuộc về mỗi phân vùng.

  • Phân vùng theo băm: Sử dụng phép chia dư của giá trị băm khóa để xác định phân vùng tương ứng.

Ngoài ra, nếu các phương pháp trên không đáp ứng yêu cầu, có thể sử dụng phương pháp thay thế như thừa kế và view UNION ALL. Tuy nhiên, những phương pháp này không có lợi thế về hiệu suất.

1. Phân Vùng Khai Báo

PostgreSQL cho phép thực hiện phân vùng bảng bằng cách khai báo. Bảng bị phân vùng gọi là bảng phân vùng, câu lệnh khai báo bao gồm các phương pháp phân vùng đã liệt kê và một nhóm cột hoặc biểu thức làm khóa phân vùng.

Bản thân bảng phân vùng là một “bảng ảo”, không có nơi lưu trữ riêng; lưu trữ thuộc về các phân vùng, và các phân vùng này là các bảng thông thường liên kết với bảng phân vùng.

Khi chèn dữ liệu vào bảng phân vùng, các hàng sẽ được định tuyến đến phân vùng tương ứng dựa trên khóa phân vùng. Cập nhật khóa phân vùng cũng có thể khiến dữ liệu rơi vào phân vùng khác.

Phân vùng bản thân cũng có thể được định nghĩa là bảng phân vùng, dẫn đến con phân vùng. Tất cả các phân vùng phải có cùng cấu trúc cột với bảng phân vùng, nhưng các phân vùng có thể có chỉ mục, ràng buộc và giá trị mặc định riêng, có thể khác nhau giữa các phân vùng.

Không thể chuyển đổi bảng thông thường thành bảng phân vùng và ngược lại. Tuy nhiên, có thể thêm bảng thông thường hoặc bảng phân vùng sẵn có làm phân vùng của bảng phân vùng, hoặc xóa phân vùng khỏi bảng phân vùng để chuyển nó thành bảng độc lập, điều này có thể đơn giản hóa và tăng tốc nhiều quy trình bảo trì.

1.1 Tạo Phân Vùng

Giả sử chúng ta đang xây dựng bảng i99bet cơ sở dữ liệu cho nghiệp vụ nhật ký lớn, cấu trúc bảng có thể như sau:

CREATE TABLE log_history (id INT NOT NULL, content TEXT, logdate DATE NOT NULL);

Giả sử rằng truy vấn nhật ký thường giới hạn trong một năm, dữ liệu gần đây được truy vấn thường xuyên hơn, và dữ liệu xa hơn được truy vấn ít hơn. Trường hợp này rất phù hợp để sử dụng phân vùng nhằm đạt được yêu cầu về hiệu suất.

Tạo bảng phân vùng

-- Sử dụng phương pháp phân vùng theo khoảng
CREATE TABLE log_history (id INT NOT NULL, content TEXT, logdate DATE NOT NULL) PARTITION BY RANGE(logdate);

Tạo phân vùng

-- Đối với dữ liệu từ năm 2010 đến 2022, mỗi năm lưu vào một phân vùng, khoảng đóng trái mở phải
CREATE TABLE log_history_2010 PARTITION OF log_history FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
CREATE TABLE log_history_2011 PARTITION OF log_history FOR VALUES FROM ('2011-01-01') TO ('2012-01-01');
CREATE TABLE log_history_2012 PARTITION OF log_history FOR VALUES FROM ('2012-01-01') TO ('2013-01-01');
...
CREATE TABLE log_history_2022 PARTITION OF log_history FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');

Dữ liệu năm 2023 còn mới và được sử dụng thường xuyên hơn, vì vậy nếu muốn phân con thêm cho phân vùng log_history_2023, có thể làm như sau:

CREATE TABLE log_history_2023 PARTITION OF log_history FOR VALUES FROM ('2023-01-01') TO ('2024-01-01') PARTITION BY RANGE(logdate);
-- Sau khi phân theo năm, tiếp tục phân theo tháng
CREATE TABLE log_history_2023_01 PARTITION OF log_history_2023 FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');
CREATE TABLE log_history_2023_02 PARTITION OF log_history_2023 FOR VALUES FROM ('2023-02-01') TO ('2023-03-01');
CREATE TABLE log_history_2023_03 PARTITION OF log_history_2023 FOR VALUES FROM ('2023-03-01') TO ('2023-04-01');
...
CREATE TABLE log_history_2023_12 PARTITION OF log_history_2023 FOR VALUES FROM ('2023-12-01') TO ('2024-01-01');

Sau khi tất cả các phân vùng được tạo, có thể tạo chỉ mục trên bảng phân vùng, điều này sẽ tự động tạo các chỉ mục khớp trên mỗi phân vùng.

CREATE INDEX ON log_history (logdate);

Lưu ý: Đảm bảo rằng tham số cấu hình enable_partition_pruning trong tệp postgresql.conf không bị vô hiệu hóa. Nếu không, truy vấn sẽ không được tối ưu theo yêu cầu.

1.2 Bảo Trì Phân Vùng

Thông thường, nhóm phân vùng được xác định ban đầu khi tạo bảng không cố định mà thường xuyên thay đổi động, chẳng hạn như xóa phân vùng cũ và thêm phân vùng mới. Lúc này, ưu điểm của phân vùng sẽ nổi bật, tức là thao tác cấu trúc phân vùng dễ dàng hơn so với di chuyển dữ liệu vật lý.

Cách đơn giản nhất để xóa dữ liệu cũ là xóa phân vùng không cần thiết:

DROP TABLE log_history_2010;

Do cách này không xóa từng dòng riêng lẻ, có thể xóa nhanh chóng hàng triệu dòng. Tuy nhiên, cần lưu ý rằng lệnh trên yêu cầu khóa ACCESS EXCLUSIVE trên bảng cha.

Thông thường, cách được khuyến nghị hơn là tách phân vùng khỏi bảng phân vùng nhưng vẫn giữ quyền truy cập vào phân vùng như một bảng thông thường. Có hai dạng:

ALTER TABLE log_history DETACH PARTITION log_history_2010;
ALTER TABLE log_history DETACH PARTITION log_history_2010 CONCURRENTLY;

Dạng thứ nhất yêu cầu khóa ACCESS EXCLUSIVE trên bảng cha; dạng thứ hai (thêm tùy chọn CONCURRENTLY) chỉ yêu cầu khóa SHARE UPDATE EXCLUSIVE trên bảng cha.

Như vậy, có thể thực hiện các thao tác dọn dẹp trước khi xóa dữ liệu, chẳng hạn như sử dụng lệnh COPY, pg_dump để sao lưu dữ liệu.

Tương tự, có thể thêm phân vùng mới cho dữ liệu sắp tới:

CREATE TABLE log_history_2024 PARTITION OF log_history FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

Một phương pháp được khuyến nghị khác là tạo bảng mới bên ngoài cấu trúc phân vùng, sau đó đính kèm nó làm phân vùng của bảng phân vùng. Điều này đảm bảo rằng dữ liệu mới đã được tải, kiểm tra và chuyển đổi trước khi được chèn vào bảng phân vùng. Hơn nữa, lệnh ATTACH PARTITION chỉ yêu cầu khóa SHARE UPDATE EXCLUSIVE trên bảng phân vùng thay vì khóa ACCESS EXCLUSIVE như lệnh CREATE TABLE ... PARTITION OF, do đó thân thiện hơn với hoạt động song song trên bảng phân vùng.

Ví dụ tạo bảng mới và đính kèm làm phân vùng của bảng phân vùng:

-- Lệnh CREATE TABLE ... LIKE giúp tránh phải lặp lại định nghĩa của bảng cha
CREATE TABLE log_history_2024 (LIKE log_history INCLUDING DEFAULTS INCLUDING CONSTRAINTS);

-- Đề xuất tạo ràng buộc CHECK phù hợp trên bảng cần đính kèm
ALTER TABLE log_history_2024 ADD CONSTRAINT logdate_check CHECK (logdate >= DATE '2024-01-01' AND logdate < DATE '2025-01-01');

-- Thực hiện các công việc chuẩn bị dữ liệu như COPY
\copy [game nhà cái tặng tiền cược miễn phí](/post/how-to-use-github-auth-in-flask/)  log_history_2024 from 'log_history_2024'

-- Thực hiện lệnh ATTACH PARTITION
ALTER TABLE log_history ATTACH PARTITION log_history_2024 FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

-- Xóa ràng buộc CHECK dư thừa sau khi hoàn thành ATTACH PARTITION
ALTER TABLE log_history_2024 DROP CONSTRAINT logdate_check;

Bài viết tiếp tục chi tiết các khía cạnh khác liên quan đến phân vùng PostgreSQL theo tài liệu chính thức phiên bản 16.