Wersja 10 PostgreSQL dodała deklaratywne partycjonowanie tabeli funkcja.W wersji 11 (obecnie w wersji beta) możesz połączyć to z obcymi datawrapperami , zapewniając mechanizm do natywnego dzielenia tabel na wiele serwerów PostgreSQL.
Partycjonowanie deklaratywne
Rozważ tabelę, która przechowuje dzienne minimalne i maksymalne temperatury w miastach na każdy dzień:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
);
Specyfikacja tabeli jest celowo pozbawiona ograniczeń dotyczących kolumn i klucza podstawowego, aby wszystko było proste – dodamy je później.
Bardzo często zdarza się, że w wielu aplikacjach częściej uzyskuje się dostęp do najnowszych danych. Pomyśl o bieżącym roku finansowym, bieżącym miesiącu, ostatniej godzinie i tak dalej. Gdy nasza tabela „temperatur” rośnie, sensowne jest przeniesienie starych danych do innej tabeli o tej samej strukturze. Możemy na przykład zrobić to:
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;
przenieść wszystkie wpisy z roku 2017 do innej tabeli. Powoduje to, że główna tabela „temperatur” jest mniejsza i szybsza, aby aplikacja mogła działać. Jako bonus, jeśli teraz musisz usunąć stare dane, możesz to zrobić bez spowalniania wstawiania danych przychodzących do głównej/bieżącej tabeli, ponieważ stare dane są aktywne w innym stole.
Jednak posiadanie wielu odrębnych tabel oznacza, że kod aplikacji musi się teraz zmienić. Jeśli musi uzyskać dostęp do starszych danych, na przykład uzyskać roczne minimalne i maksymalne temperatury miasta, musi teraz dowiedzieć się, jakie tabele są obecne w schemacie, wykonać zapytanie do każdej z nich i połączyć wyniki z każdej tabeli. Czy możemy to zrobić bez zmiany kodu aplikacji?
Umożliwia to partycjonowanie. W PostgreSQL 10 możesz utworzyć tabelę „temperatur” w następujący sposób:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
)
PARTITION BY RANGE (at);
To sprawia, że „temperatury” są główną tabelą partycji i mówi PostgreSQL, że zamierzamy utworzyć wiele podzielonych na partycje tabel przechowujących nienakładające się dane, z których każda ma inny zestaw wartości „at”. Sama tabela główna nie przechowuje żadnych danych, ale może być odpytywana przez aplikację i do niej wstawiana – co nie uwzględnia partycji podrzędnych przechowujących rzeczywiste dane.
A oto nasze partycje:
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');
Mamy teraz dwie tabele, jedną, która będzie przechowywać dane za rok 2017, a drugą za rok 2018.Pamiętaj, że wartość „od” jest inkluzywna, ale wartość „do” już nie.Wypróbujmy to:
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)
„Aplikacja” może wstawiać i wybierać z głównej tabeli, ale PostgreSQL kieruje rzeczywiste dane do odpowiednich tabel podrzędnych. (Och i przy okazji, te temperatury są prawdziwe!)
Indeksy i ograniczenia
Indeksy oraz ograniczenia tabeli i kolumny są w rzeczywistości definiowane na poziomie partycji, ponieważ tam znajdują się rzeczywiste dane. Możesz ustawić te podczas tworzenia tablicy partycji:
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 pozwala zdefiniować indeksy w tabeli nadrzędnej i utworzy indeksy w istniejących i przyszłych tabelach partycji. Przeczytaj więcej tutaj.
Opakowanie danych zagranicznych
Funkcjonalność opakowania danych obcych istnieje w Postgresie od jakiegoś czasu. Dzięki temu mechanizmowi PostgreSQL umożliwia dostęp do danych przechowywanych na innych serwerach i systemach. Interesuje nas „postgres_fdw”, co pozwoli nam uzyskać dostęp do jednego serwera Postgres z innego.
„postgres_fdw” to rozszerzenie obecne w standardowej dystrybucji, które można zainstalować za pomocą zwykłego polecenia CREATE EXTENSION:
CREATE EXTENSION postgres_fdw;
Załóżmy, że masz inny serwer PostgreSQL „box2” z bazą danych o nazwie „box2db”. W tym celu możesz utworzyć „obcy serwer”:
CREATE SERVER box2 FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'box2', dbname 'box2db');
Zmapujmy również naszego użytkownika „alice” (użytkownika, jako którego jesteś zalogowany) na użytkownika box2 „box2alice”. Dzięki temu „alice” może być „box2alice” podczas uzyskiwania dostępu do zdalnych tabel:
CREATE USER MAPPING FOR alice SERVER box2
OPTIONS (user 'box2alice');
Możesz teraz uzyskać dostęp do tabel (także widoków, widoków mat itp.) na box2. Najpierw utwórz tabelę na polu 2, a następnie „obcą tabelę” na swoim serwerze. Obca tabela nie przechowuje żadnych rzeczywistych danych, ale służy jako proxy dostępu do tabeli na polu2.
-- on box2
CREATE TABLE foo (a int);
-- on your server
IMPORT FOREIGN SCHEMA public LIMIT TO (foo)
FROM SERVER box2 INTO public;
Stół obcy na twoim serwerze może uczestniczyć w transakcjach w taki sam sposób, jak zwykłe stoły. Aplikacje nie muszą wiedzieć, że tabele, z którymi wchodzi w interakcję, są lokalne czy obce — chociaż jeśli Twoja aplikacja uruchamia polecenie SELECT, które może pobierać wiele wierszy z obcej tabeli, może to spowolnić działanie. i agreguje do zdalnego serwera.
Łączenie partycjonowania i FDW
A teraz zabawna część:konfigurowanie partycji na zdalnych serwerach.
Najpierw utwórzmy tablicę partycji fizycznych na polu 2:
-- on box2
CREATE TABLE temperatures_2016 (
at date,
city text,
mintemp integer,
maxtemp integer
);
A następnie utwórz partycję na swoim serwerze jako obcą tabelę:
CREATE FOREIGN TABLE temperatures_2016
PARTITION OF temperatures
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01')
SERVER box2;
Możesz teraz wstawiać i wysyłać zapytania z własnego serwera:
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)
Masz to! Możliwość wstawiania wierszy do zdalnej partycji to nowość w wersji 11. Dzięki tej funkcji możesz teraz logicznie (partycje) i fizycznie (FDW) podzielić dane na części.
Zarządzanie danymi
Polecenia takie jak VACUUM i ANALYZE działają zgodnie z oczekiwaniami z tabelami głównymi partycji — wszystkie lokalne tabele podrzędne podlegają VACUUM i ANALYZE. Partycje można odłączyć, ich danymi można manipulować bez ograniczenia partycji, a następnie ponownie dołączyć. Same tabele podrzędne partycjonowania mogą być partycjonowane.
Przenoszenie danych („resharding”) można wykonać za pomocą zwykłych instrukcji SQL (wstaw, usuń, kopiuj itp.). Można tworzyć lokalne indeksy i wyzwalacze partycji.
Dodanie nadmiarowości do shardów można łatwo osiągnąć dzięki replikacji logicznej lub strumieniowej.