Trong Postgres 10, "Phân vùng khai báo" đã được giới thiệu, có thể giúp bạn giải quyết rất nhiều công việc như tạo trình kích hoạt hoặc quy tắc với các câu lệnh if / else khổng lồ chuyển hướng đến bảng chính xác. Postgres có thể tự động làm việc này ngay bây giờ. Hãy bắt đầu với việc di chuyển:
-
Đổi tên bảng cũ và tạo một bảng được phân vùng mới
alter table myTable rename to myTable_old; create table myTable_master( forDate date not null, key2 int not null, value int not null ) partition by range (forDate);
Điều này hầu như không cần bất kỳ lời giải thích nào. Bảng cũ được đổi tên (sau khi di chuyển dữ liệu, chúng tôi sẽ xóa nó) và chúng tôi nhận được một bảng chính cho phân vùng của chúng tôi về cơ bản giống với bảng gốc của chúng tôi, nhưng không có chỉ mục)
-
Tạo một hàm có thể tạo các phân vùng mới khi chúng ta cần:
create function createPartitionIfNotExists(forDate date) returns void as $body$ declare monthStart date := date_trunc('month', forDate); declare monthEndExclusive date := monthStart + interval '1 month'; -- We infer the name of the table from the date that it should contain -- E.g. a date in June 2005 should be int the table mytable_200506: declare tableName text := 'mytable_' || to_char(forDate, 'YYYYmm'); begin -- Check if the table we need for the supplied date exists. -- If it does not exist...: if to_regclass(tableName) is null then -- Generate a new table that acts as a partition for mytable: execute format('create table %I partition of myTable_master for values from (%L) to (%L)', tableName, monthStart, monthEndExclusive); -- Unfortunatelly Postgres forces us to define index for each table individually: execute format('create unique index on %I (forDate, key2)', tableName); end if; end; $body$ language plpgsql;
Điều này sẽ hữu ích sau này.
-
Tạo một dạng xem về cơ bản chỉ ủy quyền cho bảng chính của chúng ta:
create or replace view myTable as select * from myTable_master;
-
Tạo quy tắc để khi chúng tôi chèn vào quy tắc, chúng tôi sẽ không chỉ cập nhật bảng đã phân vùng mà còn tạo một phân vùng mới nếu cần:
Thay vào đó,create or replace rule autoCall_createPartitionIfNotExists as on insert to myTable do instead ( select createPartitionIfNotExists(NEW.forDate); insert into myTable_master (forDate, key2, value) values (NEW.forDate, NEW.key2, NEW.value) );
Tất nhiên, nếu bạn cũng cần update
và delete
, bạn cũng cần một quy tắc cho những quy tắc đó phải được thực hiện ngay.
-
Trên thực tế, hãy di chuyển bảng cũ:
-- Finally copy the data to our new partitioned table insert into myTable (forDate, key2, value) select * from myTable_old; -- And get rid of the old table drop table myTable_old;
Giờ đây, quá trình di chuyển bảng đã hoàn tất mà không cần biết có bao nhiêu phân vùng cần thiết và cả chế độ xem myTable
sẽ được minh bạch tuyệt đối. Bạn có thể đơn giản chèn và chọn từ bảng đó như trước đây, nhưng bạn có thể nhận được lợi ích về hiệu suất từ việc phân vùng.
Lưu ý rằng chế độ xem chỉ cần thiết vì một bảng được phân vùng không thể có trình kích hoạt hàng. Nếu bạn có thể hòa nhập với việc gọi createPartitionIfNotExists
theo cách thủ công bất cứ khi nào cần từ mã của bạn, bạn không cần chế độ xem và tất cả các quy tắc của nó. Trong trường hợp này, bạn cần phải thêm các phân vùng theo cách thủ công trong quá trình di chuyển:
do
$$
declare rec record;
begin
-- Loop through all months that exist so far...
for rec in select distinct date_trunc('month', forDate)::date yearmonth from myTable_old loop
-- ... and create a partition for them
perform createPartitionIfNotExists(rec.yearmonth);
end loop;
end
$$;