PostgreSQL versi 10 menambahkan partisi tabel deklaratif fitur. Dalam versi 11 (saat ini dalam versi beta), Anda dapat menggabungkan ini dengan pembungkus data asing , menyediakan mekanisme untuk melakukan sharding tabel Anda di beberapa serverPostgreSQL.
Partisi Deklaratif
Pertimbangkan tabel yang menyimpan suhu minimum dan maksimum harian kota untuk setiap hari:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
);
Spesifikasi tabel sengaja tidak memiliki batasan kolom dan kunci utama untuk menjaga semuanya tetap sederhana – kami akan menambahkannya nanti.
Sangat umum untuk menemukan bahwa di banyak aplikasi, data terbaru lebih sering diakses. Pikirkan tahun keuangan saat ini, bulan ini, jam terakhir dan seterusnya. Saat tabel "suhu" kami tumbuh, masuk akal untuk memindahkan data lama ke tabel lain, dengan struktur yang sama. Misalnya, kita dapat melakukan ini:
CREATE TABLE temperatures_2017 (LIKE temperatures);
INSERT INTO temperatures_2017 SELECT * FROM temperatures WHERE
extract(year from at) = 2017;
DELETE FROM temperatures WHERE extract(year from at) = 2017;
untuk memindahkan semua entri dari tahun 2017 ke tabel lain. Ini membuat tabel "suhu" utama lebih kecil dan lebih cepat untuk digunakan oleh aplikasi. Sebagai bonus, jika sekarang Anda perlu menghapus data lama, Anda dapat melakukannya tanpa memperlambat penyisipan data yang masuk ke tabel utama/saat ini karena data lama tetap ada di tabel lain.
Tetapi memiliki banyak tabel yang berbeda berarti kode aplikasi sekarang harus berubah. Jika harus mengakses data yang lebih lama, katakanlah mendapatkan suhu minimum dan maksimum tahunan sebuah kota, sekarang ia harus mencari tahu tabel apa yang ada dalam skema, menanyakan masing-masing tabel dan menggabungkan hasil dari setiap tabel. Bisakah kita melakukannya tanpa mengubah kode aplikasi?
Partisi memungkinkan ini. Di PostgreSQL 10, Anda dapat membuat tabel “suhu” seperti ini:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
)
PARTITION BY RANGE (at);
Ini membuat "temperatur" menjadi tabel master partisi, dan memberi tahu PostgreSQL bahwa kita akan membuat beberapa tabel yang dipartisi untuk menyimpan data yang tidak tumpang tindih, masing-masing dengan kumpulan nilai "at" yang berbeda. Tabel master itu sendiri tidak menyimpan data apa pun, tetapi dapat ditanyakan dari dan dimasukkan ke oleh aplikasi – yang mengabaikan partisi anak yang menyimpan data aktual.
Dan inilah partisi kami:
CREATE TABLE temperatures_2017
PARTITION OF temperatures
FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');
CREATE TABLE temperatures_2018
PARTITION OF temperatures
FOR VALUES FROM ('2018-01-01') TO ('2019-01-01');
Kami sekarang memiliki dua tabel, satu yang akan menyimpan data untuk 2017 dan satu lagi untuk 2018. Perhatikan bahwa nilai "dari" termasuk, tetapi nilai "ke" tidak. Mari kita coba:
temp=# INSERT INTO temperatures (at, city, mintemp, maxtemp)
temp-# VALUES ('2018-08-03', 'London', 63, 90);
INSERT 0 1
temp=# INSERT INTO temperatures (at, city, mintemp, maxtemp)
temp-# VALUES ('2017-08-03', 'London', 59, 70);
INSERT 0 1
temp=# SELECT * FROM temperatures;
at | city | mintemp | maxtemp
------------+--------+---------+---------
2017-08-03 | London | 59 | 70
2018-08-03 | London | 63 | 90
(2 rows)
temp=# SELECT * FROM temperatures_2017;
at | city | mintemp | maxtemp
------------+--------+---------+---------
2017-08-03 | London | 59 | 70
(1 row)
temp=# SELECT * FROM temperatures_2018;
at | city | mintemp | maxtemp
------------+--------+---------+---------
2018-08-03 | London | 63 | 90
(1 row)
"Aplikasi" dapat menyisipkan dan memilih dari tabel utama, tetapi PostgreSQL merutekan data aktual ke tabel anak yang sesuai. (Oh dan BTW, suhu itu nyata!)
Indeks dan Batasan
Indeks dan batasan tabel dan kolom sebenarnya ditentukan pada tingkat yang dapat dipartisi, karena di situlah data aktual berada. Anda dapat mengatur ini selama pembuatan tabel partisi:
CREATE TABLE temperatures_2017
PARTITION OF temperatures (
mintemp NOT NULL,
maxtemp NOT NULL,
CHECK (mintemp <= maxtemp),
PRIMARY KEY (at, city)
)
FOR VALUES FROM ('2017-01-01') TO ('2018-01-01');
PostgreSQL 11 memungkinkan Anda menentukan indeks pada tabel induk, dan akan membuat indeks pada tabel partisi yang ada dan yang akan datang. Baca selengkapnya di sini.
Pembungkus Data Asing
Fungsi pembungkus data asing telah ada di Postgres selama beberapa waktu. PostgreSQL memungkinkan Anda mengakses data yang disimpan di server dan sistem lain menggunakan mekanisme ini. Yang kami minati adalah “postgres_fdw”, yang memungkinkan kami mengakses satu server Postgres dari yang lain.
“postgres_fdw” adalah ekstensi yang ada dalam distribusi standar, yang dapat diinstal dengan perintah CREATE EXTENSION biasa:
CREATE EXTENSION postgres_fdw;
Mari kita asumsikan Anda memiliki server PostgreSQL lain "box2" dengan database yang disebut "box2db". Anda dapat membuat "server asing" untuk ini:
CREATE SERVER box2 FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'box2', dbname 'box2db');
Mari kita juga memetakan pengguna "alice" (pengguna yang Anda gunakan untuk masuk) ke pengguna box2 "box2alice". Ini memungkinkan "alice" menjadi "box2alice" saat mengakses tabel jarak jauh:
CREATE USER MAPPING FOR alice SERVER box2
OPTIONS (user 'box2alice');
Anda sekarang dapat mengakses tabel (juga tampilan, matviews dll) di box2. Pertama, buat tabel di box2, lalu "tabel asing" di server Anda. Tabel asing tidak menyimpan data aktual apa pun, tetapi berfungsi sebagai proxy untuk mengakses tableon box2.
-- on box2
CREATE TABLE foo (a int);
-- on your server
IMPORT FOREIGN SCHEMA public LIMIT TO (foo)
FROM SERVER box2 INTO public;
Tabel asing di server Anda dapat berpartisipasi dalam transaksi dengan cara yang sama seperti tabel biasa. Aplikasi tidak harus tahu bahwa tabel yang berinteraksi dengannya adalah lokal atau asing – meskipun jika aplikasi Anda menjalankan SELECT yang mungkin menarik banyak baris dari tabel asing, hal itu mungkin memperlambat segalanya. Di Postgres 10, perbaikan dilakukan untuk menekan gabungan dan digabungkan ke server jarak jauh.
Menggabungkan Partisi dan PLRT Asing
Dan sekarang untuk bagian yang menyenangkan:menyiapkan partisi di server jarak jauh.
Pertama, mari kita buat tabel partisi fisik di box2:
-- on box2
CREATE TABLE temperatures_2016 (
at date,
city text,
mintemp integer,
maxtemp integer
);
Dan kemudian buat partisi di server Anda, sebagai tabel asing:
CREATE FOREIGN TABLE temperatures_2016
PARTITION OF temperatures
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01')
SERVER box2;
Sekarang Anda dapat menyisipkan dan membuat kueri dari server Anda sendiri:
temp=# INSERT INTO temperatures (at, city, mintemp, maxtemp)
temp-# VALUES ('2016-08-03', 'London', 63, 73);
INSERT 0 1
temp=# SELECT * FROM temperatures ORDER BY at;
at | city | mintemp | maxtemp
------------+--------+---------+---------
2016-08-03 | London | 63 | 73
2017-08-03 | London | 59 | 70
2018-08-03 | London | 63 | 90
(3 rows)
temp=# SELECT * FROM temperatures_2016;
at | city | mintemp | maxtemp
------------+--------+---------+---------
2016-08-03 | London | 63 | 73
(1 row)
Di sana Anda memilikinya! Kemampuan untuk menyisipkan baris ke dalam partisi jarak jauh adalah hal baru di versi 11. Dengan fitur ini, Anda sekarang dapat membagi data Anda secara logis (partisi) dan fisik (FDW).
Pengelolaan Data
Perintah seperti VACUUM dan ANALYZE berfungsi seperti yang Anda harapkan dengan tabel master partisi– semua tabel anak lokal tunduk pada VACUUM dan ANALYZE. Partisi dapat di-detach, datanya dimanipulasi tanpa batasan partisi, dan kemudian disambungkan kembali. Tabel anak partisi sendiri dapat dipartisi.
Memindahkan data ("reharding") dapat dilakukan dengan pernyataan SQL biasa (menyisipkan, menghapus, menyalin, dll.). Indeks dan pemicu partisi-lokal dapat dibuat.
Menambahkan redundansi ke shard Anda dapat dengan mudah dicapai dengan logika atau replikasi streaming.