Di Postgres 10 "Partisi Deklaratif" diperkenalkan, yang dapat membebaskan Anda dari banyak pekerjaan seperti menghasilkan pemicu atau aturan dengan pernyataan if/else besar yang mengarahkan ke tabel yang benar. Postgres dapat melakukan ini secara otomatis sekarang. Mari kita mulai dengan migrasi:
-
Ganti nama tabel lama dan buat tabel baru yang dipartisi
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);
Ini seharusnya tidak memerlukan penjelasan apa pun. Tabel lama diganti namanya (setelah migrasi data kami akan menghapusnya) dan kami mendapatkan tabel master untuk partisi kami yang pada dasarnya sama dengan tabel asli kami, tetapi tanpa indeks)
-
Buat fungsi yang dapat menghasilkan partisi baru saat kita membutuhkannya:
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;
Ini akan berguna nanti.
-
Buat tampilan yang pada dasarnya hanya didelegasikan ke tabel master kami:
create or replace view myTable as select * from myTable_master;
-
Buat rule agar ketika kita memasukkan rule, kita tidak hanya mengupdate tabel yang telah dipartisi, tetapi juga membuat partisi baru jika diperlukan:
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) );
Tentu saja, jika Anda juga membutuhkan update
dan delete
, Anda juga memerlukan aturan untuk aturan yang harus lurus ke depan.
-
Sebenarnya migrasikan tabel lama:
-- 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;
Sekarang migrasi tabel selesai tanpa perlu mengetahui berapa banyak partisi yang dibutuhkan dan juga tampilan myTable
akan benar-benar transparan. Anda dapat dengan mudah menyisipkan dan memilih dari tabel itu seperti sebelumnya, tetapi Anda mungkin mendapatkan manfaat kinerja dari mempartisi.
Perhatikan bahwa tampilan hanya diperlukan, karena tabel yang dipartisi tidak dapat memiliki pemicu baris. Jika Anda bisa bergaul dengan menelepon createPartitionIfNotExists
secara manual kapan pun diperlukan dari kode Anda, Anda tidak memerlukan tampilan dan semua aturannya. Dalam hal ini Anda perlu menambahkan partisi juga secara manual selama migrasi:
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
$$;