Version 10 af PostgreSQL tilføjede den deklarative tabelpartitionering feature.I version 11 (i øjeblikket i beta) kan du kombinere dette med udenlandske dataindpakninger , der giver en mekanisme til at sønderdele dine borde på tværs af flere PostgreSQL-servere.
Deklarativ partitionering
Overvej en tabel, der gemmer de daglige minimum- og maksimumtemperaturer for byer for hver dag:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
);
Tabelspecifikationen er med vilje blottet for kolonnebegrænsninger og primær nøgle for at holde tingene enkle – vi tilføjer dem senere.
Det er meget almindeligt at opdage, at i mange applikationer er de nyeste data oftere tilgået. Tænk på nuværende regnskabsår, denne måned, sidste time og så videre. Efterhånden som vores "temperaturer"-tabel vokser, giver det mening at flytte de gamle data ud til en anden tabel med samme struktur. Vi kan for eksempel gøre dette:
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;
at flytte alle poster fra år 2017 til en anden tabel. Dette efterlader hoved-"temperaturtabellen" mindre og hurtigere for applikationen at arbejde med. Som en bonus, hvis du nu har brug for at slette gamle data, kan du gøre det uden at bremse indsættelser af indgående data i hoved-/aktuelle tabel, fordi de gamle data lever i en anden tabel.
Men at have flere, adskilte tabeller betyder, at applikationskoden nu skal ændres. Hvis den skal have adgang til ældre data, f.eks. at få de årlige min- og makstemperaturer for en by, skal den nu finde ud af, hvilke tabeller der findes i skemaet, forespørge på hver af dem og kombinere resultaterne fra hver tabel. Kan vi gøre dette uden at ændre applikationskoden?
Opdeling gør dette muligt. I PostgreSQL 10 kan du oprette "temperaturer"-tabellen sådan her:
CREATE TABLE temperatures (
at date,
city text,
mintemp integer,
maxtemp integer
)
PARTITION BY RANGE (at);
Dette gør "temperaturer" til en partitionsmastertabel og fortæller PostgreSQL, at vi vil oprette flere partitionerede tabeller, der lagrer ikke-overlappende data, hver med et andet sæt "ved"-værdier. Mastertabellen i sig selv indeholder ingen data, men kan forespørges fra og indsættes i af applikationen - som er uvidende om de underordnede partitioner, der indeholder de faktiske data.
Og her er vores skillevægge:
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');
Vi har nu to tabeller, en som vil gemme data for 2017 og en anden for 2018. Bemærk, at "fra"-værdien er inklusive, men "til"-værdien er det ikke. Lad os prøve det:
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)
"Applikationen" er i stand til at indsætte i og vælge fra hovedtabellen, men PostgreSQL dirigerer de faktiske data til de relevante underordnede tabeller. (Åh og BTW, de temperaturer er rigtige!)
Indekser og begrænsninger
Indekser og tabel- og kolonnebegrænsninger er faktisk defineret på partitionstabelniveauet, da det er der, de faktiske data ligger. Du kan indstille disse under oprettelsen af partitionstabellen:
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 lader dig definere indekser på den overordnede tabel, og vil oprette indekser på eksisterende og fremtidige partitionstabeller. Læs mere her.
Foreign Data Wrapper
Den udenlandske dataindpakningsfunktion har eksisteret i Postgres i nogen tid. PostgreSQL giver dig adgang til data gemt på andre servere og systemer ved hjælp af denne mekanisme. Det, vi er interesseret i, er "postgres_fdw", som er det, der vil give os adgang til en Postgres-server fra en anden.
"postgres_fdw" er en udvidelse til stede i standarddistributionen, som kan installeres med den almindelige CREATE EXTENSION kommando:
CREATE EXTENSION postgres_fdw;
Lad os antage, at du har en anden PostgreSQL-server "box2" med en database kaldet "box2db". Du kan oprette en "fremmed server" til dette:
CREATE SERVER box2 FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'box2', dbname 'box2db');
Lad os også kortlægge vores bruger "alice" (den bruger du er logget ind som) til box2 bruger "box2alice". Dette tillader "alice" at være "box2alice", når du får adgang til fjerntabeller:
CREATE USER MAPPING FOR alice SERVER box2
OPTIONS (user 'box2alice');
Du kan nu få adgang til tabeller (også visninger, matviews osv.) på box2. Først skal du oprette en tabel på box2, og derefter en "fremmed tabel" på din server. De udenlandske tables indeholder ingen faktiske data, men tjener som proxy for adgang til tableon box2.
-- on box2
CREATE TABLE foo (a int);
-- on your server
IMPORT FOREIGN SCHEMA public LIMIT TO (foo)
FROM SERVER box2 INTO public;
Det udenlandske bord på din server kan deltage i transaktioner på samme måde som normale borde. Applikationer behøver ikke at vide, at de tabeller, den interagerer med, er lokale eller udenlandske – selvom hvis din app kører en SELECT, som kan trække mange rækker ind fra en udenlandsk tabel, kan det gøre tingene langsommere. I Postgres 10 blev der lavet forbedringer til at skubbe joins ned. og samles til fjernserveren.
Kombinering af partitionering og FDW
Og nu til den sjove del:opsætning af partitioner på fjernservere.
Lad os først oprette den fysiske partitionstabel på box2:
-- on box2
CREATE TABLE temperatures_2016 (
at date,
city text,
mintemp integer,
maxtemp integer
);
Og opret derefter partitionen på din server som en fremmed tabel:
CREATE FOREIGN TABLE temperatures_2016
PARTITION OF temperatures
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01')
SERVER box2;
Du kan nu indsætte og forespørge fra din egen server:
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)
Der har du det! At være i stand til at indsætte rækker i en fjernpartition er ny i version 11. Med denne funktion kan du nu få dine data delt logisk (partitioner) og fysisk (FDW).
Datastyring
Kommandoer som VACUUM og ANALYSE fungerer, som du ville forvente med partitionsmastertabeller – alle lokale underordnede tabeller er underlagt VACUUM og ANALYSE. Partitioner kan adskilles, det er data, der manipuleres uden partitionsbegrænsningen og derefter vedhæftes igen. Selve underordnede partitioneringstabeller kan partitioneres.
Flytning af data (“resharding”) kan gøres med almindelige SQL-sætninger (indsæt, slet, kopier osv.). Partitionslokale indekser og triggere kan oprettes.
Tilføjelse af redundans til dine shards opnås nemt med logisk eller streamingreplikering.