PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Partage de vos données avec PostgreSQL 11

La version 10 de PostgreSQL a ajouté le partitionnement de table déclaratif fonctionnalité.Dans la version 11 (actuellement en version bêta), vous pouvez combiner cela avec des datawrappers étrangers , fournissant un mécanisme pour partitionner nativement vos tables sur plusieurs serveurs PostgreSQL.

Partitionnement déclaratif

Considérons un tableau qui stocke les températures minimales et maximales quotidiennes des villes pour chaque jour :

CREATE TABLE temperatures (
    at      date,
    city    text,
    mintemp integer,
    maxtemp integer
);

La spécification de table est intentionnellement dépourvue de contraintes de colonne et de clé primaire pour simplifier les choses - nous les ajouterons plus tard.

Il est très courant de constater que dans de nombreuses applications, les données les plus récentes sont plus fréquemment consultées. Pensez à l'année financière en cours, à ce mois-ci, à la dernière heure, etc. Au fur et à mesure que notre tableau "températures" s'agrandit, il est logique de déplacer les anciennes données vers un autre tableau, avec la même structure. Nous pouvons par exemple faire ceci :

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;

pour déplacer toutes les entrées de l'année 2017 dans une autre table. Cela laisse la table principale des « températures » plus petite et plus rapide pour que l'application puisse travailler avec. En prime, si vous avez maintenant besoin de supprimer d'anciennes données, vous pouvez le faire sans ralentir les insertions de données entrantes dans la table principale/actuelle car les anciennes données vivent dans une autre table.

Mais avoir plusieurs tables distinctes signifie que le code de l'application doit maintenant changer. S'il doit accéder à des données plus anciennes, par exemple obtenir les températures minimales et maximales annuelles d'une ville, il doit maintenant découvrir quelles tables sont présentes dans le schéma, interroger chacune d'elles et combiner les résultats de chaque table. Pouvons-nous faire cela sans changer le code de l'application ?

Le partitionnement rend cela possible. Dans PostgreSQL 10, vous pouvez créer la table « températures » comme ceci :

CREATE TABLE temperatures (
    at      date,
    city    text,
    mintemp integer,
    maxtemp integer
)
PARTITION BY RANGE (at);

Cela fait de « temperatures » une table principale de partition et indique à PostgreSQL que nous allons créer plusieurs tables partitionnées stockant des données qui ne se chevauchent pas, chacune avec un ensemble différent de valeurs « at ». La table maître elle-même ne contient aucune donnée, mais peut être interrogée et insérée par l'application - qui ignore les partitions enfants contenant les données réelles.

Et voici nos partitions :

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');

Nous avons maintenant deux tables, une qui stockera les données pour 2017 et une autre pour 2018. Notez que la valeur "de" est inclusive, mais pas la valeur "à". Essayons :

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)

L'"application" est capable d'insérer et de sélectionner dans la table principale, mais PostgreSQL achemine les données réelles vers les tables enfants appropriées. (Oh et BTW, ces températures sont réelles !)

Index et contraintes

Les index et les contraintes de table et de colonne sont en fait définis au niveau de la table de partition, puisque c'est là que résident les données réelles. Vous pouvez les définir lors de la création de la table de partition :

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 vous permet de définir des index sur la table parent et créera des index sur les tables de partition existantes et futures. En savoir plus ici.

Emballage de données étrangères

La fonctionnalité de wrapper de données étrangères existe dans Postgres depuis un certain temps. PostgreSQL vous permet d'accéder aux données stockées dans d'autres serveurs et systèmes en utilisant ce mécanisme. Ce qui nous intéresse, c'est "postgres_fdw", qui nous permettra d'accéder à un serveur Postgres à partir d'un autre.

"postgres_fdw" est une extension présente dans la distribution standard, qui peut être installée avec la commande habituelle CREATE EXTENSION :

CREATE EXTENSION postgres_fdw;

Supposons que vous ayez un autre serveur PostgreSQL "box2" avec une base de données appelée "box2db". Vous pouvez créer un "serveur étranger" pour cela :

CREATE SERVER box2 FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host 'box2', dbname 'box2db');

Associons également notre utilisateur "alice" (l'utilisateur sous lequel vous êtes connecté) à l'utilisateur box2 "box2alice". Cela permet à "alice" d'être "box2alice" lors de l'accès aux tables distantes :

CREATE USER MAPPING FOR alice SERVER box2
    OPTIONS (user 'box2alice');

Vous pouvez maintenant accéder aux tables (également vues, matviews, etc.) sur box2. Créez d'abord une table sur box2, puis une « table étrangère » sur votre serveur. La table étrangère ne contient aucune donnée réelle, mais sert de proxy pour accéder à la table sur la boîte2.

-- on box2
CREATE TABLE foo (a int);

-- on your server
IMPORT FOREIGN SCHEMA public LIMIT TO (foo)
    FROM SERVER box2 INTO public;

La table étrangère de votre serveur peut participer aux transactions de la même manière que les tables normales. Les applications n'ont pas besoin de savoir que les tables avec lesquelles elles interagissent sont locales ou étrangères - bien que si votre application exécute un SELECT qui pourrait extraire de nombreuses lignes d'une table étrangère, cela pourrait ralentir les choses. Dans Postgres 10, des améliorations ont été apportées pour pousser les jointures et s'agrège au serveur distant.

Combiner partitionnement et FDW

Et maintenant, passons à la partie amusante :configurer des partitions sur des serveurs distants.

Commençons par créer la table de partition physique sur box2 :

-- on box2
CREATE TABLE temperatures_2016 (
    at      date,
    city    text,
    mintemp integer,
    maxtemp integer
);

Et créez ensuite la partition sur votre serveur, en tant que table étrangère :

CREATE FOREIGN TABLE temperatures_2016
    PARTITION OF temperatures
    FOR VALUES FROM ('2016-01-01') TO ('2017-01-01')
    SERVER box2;

Vous pouvez désormais insérer et interroger depuis votre propre serveur :

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)

Voilà! La possibilité d'insérer des lignes dans une partition distante est une nouveauté de la version 11. Grâce à cette fonctionnalité, vous pouvez désormais partitionner vos données de manière logique (partitions) et physiquement (FDW).

Gestion des données

Des commandes telles que VACUUM et ANALYZE fonctionnent comme vous vous en doutez avec les tables maîtresses de partition - toutes les tables enfants locales sont soumises à VACUUM et ANALYZE. Les partitions peuvent être détachées, ses données manipulées sans la contrainte de partition, puis rattachées. Les tables enfants de partition elles-mêmes peuvent être partitionnées.

Le déplacement des données ("repartitionnement") peut être effectué avec des instructions SQL régulières (insertion, suppression, copie, etc.). Des index et des déclencheurs locaux à la partition peuvent être créés.

L'ajout de redondance à vos fragments est facilement réalisé avec une réplication logique ou en continu.