Версия 10 на PostgreSQL добави декларативното разделяне на таблица функция. Във версия 11 (понастоящем в бета) можете да комбинирате това с чужди обвивки на данни , осигуряващ механизъм за вътрешно разделяне на вашите таблици в множество сървъри PostgreSQL.
Декларативно разделяне
Помислете за таблица, която съхранява дневните минимални и максимални температури на градовете за всеки ден:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
);
Спецификацията на таблицата е умишлено лишена от ограничения за колони и първичен ключ, за да поддържаме нещата прости – ще ги добавим по-късно.
Много често се установява, че в много приложения най-новите данни са по-често достъпни. Помислете за текущата финансова година, този месец, последния час и така нататък. Тъй като нашата таблица с „температури“ расте, има смисъл да преместим старите данни в друга таблица със същата структура. Можем например да направим това:
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;
за да преместите всички записи от 2017 г. в друга таблица. Това оставя основната таблица с „температури“ по-малка и по-бърза, за да може приложението да работи с нея. Като бонус, ако сега трябва да изтриете стари данни, можете да го направите, без да забавяте вмъкването на входящи данни в основната/текущата таблица, тъй като старите данни се съхраняват в друга таблица.
Но наличието на множество различни таблици означава, че кодът на приложението сега трябва да се промени. Ако трябва да получи достъп до по-стари данни, да речем получаване на годишните мин. и максимални температури на даден град, сега трябва да разбере какви таблици присъстват в схемата, да потърси всяка от тях и да комбинира резултатите от всяка таблица. Можем ли да направим това без промяна на кода на приложението?
Разделянето прави това възможно. В PostgreSQL 10 можете да създадете таблица с „температури“ по следния начин:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
)
PARTITION BY RANGE (at);
Това прави „температурите“ главна таблица на дяловете и казва на PostgreSQL, че ще създадем множество разделени таблици, съхраняващи неприпокриващи се данни, всяка с различен набор от стойности „at“. Самата главна таблица не съдържа никакви данни, но може да бъде запитана и вмъкната от приложението от приложението – което не знае за дъщерните дялове, съдържащи действителните данни.
А ето и нашите дялове:
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');
Вече имаме две таблици, едната, която ще съхранява данни за 2017 г., а другата за 2018 г. Имайте предвид, че стойността „от“ включва, но стойността „до“ не е. Нека я изпробваме:
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)
„Приложението“ може да вмъква и избира от основната таблица, но PostgreSQL насочва действителните данни в съответните дъщерни таблици. (О и BTW, тези температури са реални!)
Индекси и ограничения
Индексите и ограниченията за таблици и колони всъщност са дефинирани на ниво таблица на дялове, тъй като там се намират действителните данни. Можете да зададете тези по време на създаването на таблицата на дяловете:
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 ви позволява да дефинирате индекси на родителската таблица и ще създава индекси на съществуващи и бъдещи таблици на дялове. Прочетете повече тук.
Обвивка на чужди данни
Функционалността за обвиване на чужди данни съществува в Postgres от известно време. PostgreSQL ви позволява да осъществявате достъп до данни, съхранявани в други сървъри и системи, използвайки този механизъм. Това, което ни интересува, е „postgres_fdw“, което ще ни позволи достъп до един Postgres сървър от друг.
“postgres_fdw” е разширение, присъстващо в стандартната дистрибуция, което може да се инсталира с обикновената команда CREATE EXTENSION:
CREATE EXTENSION postgres_fdw;
Да предположим, че имате друг PostgreSQL сървър „box2“ с база данни, наречена „box2db“. Можете да създадете „чужд сървър“ за това:
CREATE SERVER box2 FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'box2', dbname 'box2db');
Нека също така съпоставим нашия потребител „alice“ (потребителят, от който сте влезли) към box2 user „box2alice“. Това позволява на “alice” да бъде “box2alice” при достъп до отдалечени таблици:
CREATE USER MAPPING FOR alice SERVER box2
OPTIONS (user 'box2alice');
Вече имате достъп до таблици (също изгледи, matviews и т.н.) на box2. Първо създайте таблица на box2 и след това „чужда таблица“ на вашия сървър. Външната таблица не съдържа никакви реални данни, но служи като прокси за достъп до таблицата box2.
-- on box2
CREATE TABLE foo (a int);
-- on your server
IMPORT FOREIGN SCHEMA public LIMIT TO (foo)
FROM SERVER box2 INTO public;
Външната таблица във вашия сървър може да участва в транзакции по същия начин като нормалните таблици. Приложенията не трябва да знаят, че таблиците, с които взаимодейства, са местни или чужди – въпреки че ако приложението ви изпълнява SELECT, който може да издърпа много редове от чужда таблица, това може да забави нещата. В Postgres 10 бяха направени подобрения за натискане на съединения надолу и агрегира към отдалечения сървър.
Комбиниране на разделяне и FDW
И сега за забавната част:настройване на дялове на отдалечени сървъри.
Първо, нека създадем таблицата на физическите дялове на box2:
-- on box2
CREATE TABLE temperatures_2016 (
at date,
city text,
mintemp integer,
maxtemp integer
);
И след това създайте дяла на вашия сървър, като чужда таблица:
CREATE FOREIGN TABLE temperatures_2016
PARTITION OF temperatures
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01')
SERVER box2;
Вече можете да вмъквате и да правите заявки от собствения си сървър:
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)
Ето го! Възможността за вмъкване на редове в отдалечен дял е нова версия 11. С тази функция вече можете да разпределите данните си логически (раздели) и физически (FDW).
Управление на данни
Команди като VACUUM и ANALYZE работят както бихте очаквали с главните таблици на дялове – всички локални дъщерни таблици са обект на VACUUM и ANALYZE. Дяловете могат да се отделят, данните се манипулират без ограничението на дяла и след това се прикачват отново. Самите дъщерни таблици на дялове могат да бъдат разделени.
Преместването на данни („преразпределяне“) може да се извърши с обикновени SQL оператори (вмъкване, изтриване, копиране и т.н.). Могат да се създават локални индекси и тригери за дял.
Добавянето на излишък към вашите фрагменти се постига лесно с логическо или поточно репликация.