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

Un guide pour partitionner les données dans PostgreSQL

Qu'est-ce que le partitionnement des données ?

Pour les bases de données avec des tables extrêmement volumineuses, le partitionnement est une astuce merveilleuse et astucieuse pour les concepteurs de bases de données pour améliorer les performances de la base de données et rendre la maintenance beaucoup plus facile. La taille de table maximale autorisée dans une base de données PostgreSQL est de 32 To, mais à moins qu'elle ne soit exécutée sur un ordinateur du futur qui n'a pas encore été inventé, des problèmes de performances peuvent survenir sur une table ne disposant que d'un centième de cet espace.

Le partitionnement divise une table en plusieurs tables et se fait généralement de manière à ce que les applications accédant à la table ne remarquent aucune différence, à part être plus rapides pour accéder aux données dont elles ont besoin. En divisant la table en plusieurs tables, l'idée est de permettre à l'exécution des requêtes d'avoir à parcourir des tables et des index beaucoup plus petits pour trouver les données nécessaires. Quelle que soit l'efficacité d'une stratégie d'indexation, l'analyse d'un index pour une table de 50 Go sera toujours beaucoup plus rapide qu'un index pour une table de 500 Go. Cela s'applique également aux analyses de table, car parfois les analyses de table sont tout simplement inévitables.

Lors de l'introduction d'une table partitionnée dans le planificateur de requêtes, il y a quelques éléments à connaître et à comprendre sur le planificateur de requêtes lui-même. Avant qu'une requête ne soit réellement exécutée, le planificateur de requêtes prendra la requête et planifiera la manière la plus efficace d'accéder aux données. En répartissant les données sur différentes tables, le planificateur peut décider à quelles tables accéder et quelles tables ignorer complètement, en fonction du contenu de chaque table.

Cela se fait en ajoutant des contraintes aux tables divisées qui définissent quelles données sont autorisées dans chaque table, et avec une bonne conception, nous pouvons demander au planificateur de requêtes d'analyser un petit sous-ensemble de données plutôt que l'ensemble.

Une table doit-elle être partitionnée ?

Le partitionnement peut considérablement améliorer les performances sur une table lorsqu'il est bien fait, mais s'il est mal fait ou lorsqu'il n'est pas nécessaire, il peut aggraver les performances, voire inutilisable.

Quelle est la taille de la table ?

Il n'y a pas de véritable règle stricte quant à la taille d'une table avant que le partitionnement ne soit une option, mais en fonction des tendances d'accès à la base de données, les utilisateurs et les administrateurs de la base de données commenceront à voir les performances sur une table spécifique commencer à se dégrader à mesure qu'elle grossit. En général, le partitionnement ne doit être envisagé que lorsque quelqu'un dit "Je ne peux pas faire X car la table est trop grande". Pour certains hôtes, 200 Go pourraient être le bon moment pour partitionner, pour d'autres, il peut être temps de partitionner lorsqu'il atteint 1 To.

Si la table est jugée "trop ​​grande", il est temps d'examiner les modèles d'accès. Soit en connaissant les applications qui accèdent à la base de données, soit en surveillant les journaux et en générant des rapports de requête avec quelque chose comme pgBadger, nous pouvons voir comment une table est accédée, et selon la manière dont elle est accédée, nous pouvons avoir des options pour une bonne stratégie de partitionnement.

Pour en savoir plus sur pgBadger et son utilisation, veuillez consulter notre article précédent sur pgBadger.

Est-ce que le gonflement des tables est un problème ?

Les lignes mises à jour et supprimées entraînent des tuples morts qui doivent finalement être nettoyés. L'aspiration des tables, que ce soit manuellement ou automatiquement, passe en revue chaque ligne de la table et détermine si elle doit être récupérée ou laissée seule. Plus la table est grande, plus ce processus est long et plus les ressources système utilisées sont importantes. Même si 90 % d'une table est constituée de données immuables, elle doit être analysée à chaque fois qu'un aspirateur est exécuté. Le partitionnement de la table peut aider à réduire la table qui doit être nettoyée à des tables plus petites, réduisant ainsi la quantité de données immuables à analyser, moins de temps à nettoyer globalement et plus de ressources système libérées pour l'accès des utilisateurs plutôt que pour la maintenance du système.

Comment les données sont-elles supprimées, le cas échéant ?

Si les données sont supprimées selon un calendrier, par exemple les données de plus de 4 ans sont supprimées et archivées, cela peut entraîner des instructions de suppression lourdes qui peuvent prendre du temps à s'exécuter et, comme mentionné précédemment, créer des lignes mortes qui doivent être aspirées. Si une bonne stratégie de partitionnement est mise en œuvre, une instruction DELETE de plusieurs heures avec maintenance de vide par la suite pourrait être transformée en une instruction DROP TABLE d'une minute sur une ancienne table mensuelle sans maintenance de vide.

Comment la table doit-elle être partitionnée ?

Les clés des modèles d'accès se trouvent dans la clause WHERE et les conditions JOIN. Chaque fois qu'une requête spécifie des colonnes dans les clauses WHERE et JOIN, elle indique à la base de données "ce sont les données que je veux". Tout comme la conception d'index qui ciblent ces clauses, les stratégies de partitionnement reposent sur le ciblage de ces colonnes pour séparer les données et permettre à la requête d'accéder au moins de partitions possible.

Exemples :

  1. Une table de transactions, avec une colonne de date qui est toujours utilisée dans une clause where.
  2. Une table de clients avec des colonnes d'emplacement, telles que le pays de résidence, qui est toujours utilisée dans les clauses where.

Les colonnes les plus courantes sur lesquelles se concentrer pour le partitionnement sont généralement les horodatages, car généralement une grande partie des données sont des informations historiques et auront probablement des données plutôt prévisibles réparties sur différents groupes de temps.

Déterminer la répartition des données

Une fois que nous avons identifié les colonnes à partitionner, nous devons examiner la répartition des données, dans le but de créer des tailles de partition qui répartissent les données aussi uniformément que possible sur les différentes partitions enfants.

severalnines=# SELECT DATE_TRUNC('year', view_date)::DATE, COUNT(*) FROM website_views GROUP BY 1 ORDER BY 1;
 date_trunc |  count
------------+----------
 2013-01-01 | 11625147
 2014-01-01 | 20819125
 2015-01-01 | 20277739
 2016-01-01 | 20584545
 2017-01-01 | 20777354
 2018-01-01 |   491002
(6 rows)

Dans cet exemple, nous tronquons la colonne timestamp en une table annuelle, ce qui donne environ 20 millions de lignes par an. Si toutes nos requêtes spécifient une ou plusieurs dates ou une ou plusieurs plages de dates et que celles spécifiées couvrent généralement les données d'une seule année, cela peut être une excellente stratégie de départ pour le partitionnement, car cela donnerait une seule table par an. , avec un nombre gérable de lignes par table.

Téléchargez le livre blanc aujourd'hui PostgreSQL Management &Automation with ClusterControlDécouvrez ce que vous devez savoir pour déployer, surveiller, gérer et faire évoluer PostgreSQLTélécharger le livre blanc

Création d'une table partitionnée

Il existe plusieurs façons de créer des tables partitionnées, mais nous nous concentrerons principalement sur le type le plus riche en fonctionnalités disponible, le partitionnement basé sur les déclencheurs. Cela nécessite une configuration manuelle et un peu de codage dans le langage procédural plpgsql pour que cela fonctionne.

Il fonctionne en ayant une table parent qui finira par devenir vide (ou restera vide s'il s'agit d'une nouvelle table) et des tables enfants qui héritent de la table parent. Lorsque la table parent est interrogée, les tables enfants sont également recherchées pour les données en raison de l'INHERIT appliqué aux tables enfants. Cependant, étant donné que les tables enfants ne contiennent que des sous-ensembles des données du parent, nous ajoutons une CONSTRAINT sur la table qui effectue un CHECK et vérifie que les données correspondent à ce qui est autorisé dans la table. Cela fait deux choses :premièrement, il refuse les données qui n'appartiennent pas, et deuxièmement, il indique au planificateur de requêtes que seules les données correspondant à cette CHECK CONSTRAINT sont autorisées dans cette table, donc si vous recherchez des données qui ne correspondent pas à la table, n' même pas la peine de le chercher.

Enfin, nous appliquons un déclencheur à la table parent qui exécute une procédure stockée qui décide dans quelle table enfant placer les données.

Créer un tableau

La création de la table parent est comme toute autre création de table.

severalnines=# CREATE TABLE data_log (data_log_sid SERIAL PRIMARY KEY,
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR);
CREATE TABLE

Créer des tableaux enfants

La création des tables enfants est similaire, mais implique quelques ajouts. Pour des raisons d'organisation, nos tables enfants existeront dans un schéma séparé. Faites cela pour chaque table enfant, en modifiant les détails en conséquence.

REMARQUE :Le nom de la séquence utilisée dans nextval() provient de la séquence créée par le parent. Ceci est crucial pour que toutes les tables enfants utilisent la même séquence.

severalnines=# CREATE SCHEMA part;
CREATE SCHEMA

severalnines=# CREATE TABLE part.data_log_2018 (data_log_sid integer DEFAULT nextval('public.data_log_data_log_sid_seq'::regclass),
  date TIMESTAMP WITHOUT TIME ZONE DEFAULT NOW(),
  event_details VARCHAR)
 INHERITS (public.data_log);
CREATE TABLE

severalnines=# ALTER TABLE ONLY part.data_log_2018
    ADD CONSTRAINT data_log_2018_pkey PRIMARY KEY (data_log_sid);
ALTER TABLE

severalnines=# ALTER TABLE part.data_log_2018 ADD CONSTRAINT data_log_2018_date CHECK (date >= '2018-01-01' AND date < '2019-01-01');
ALTER TABLE

Créer une fonction et un déclencheur

Enfin, nous créons notre procédure stockée et ajoutons le déclencheur à notre table parent.

severalnines=# CREATE OR REPLACE FUNCTION 
 public.insert_trigger_table()
  RETURNS trigger
  LANGUAGE plpgsql
 AS $function$
 BEGIN
     IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
         INSERT INTO part.data_log_2018 VALUES (NEW.*);
         RETURN NULL;
     ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
         INSERT INTO part.data_log_2019 VALUES (NEW.*);
         RETURN NULL;
     END IF;
 END;
 $function$;
CREATE FUNCTION

severalnines=# CREATE TRIGGER insert_trigger BEFORE INSERT ON data_log FOR EACH ROW EXECUTE PROCEDURE insert_trigger_table();
CREATE TRIGGER

Testez-le

Maintenant que tout est créé, testons-le. Dans ce test, j'ai ajouté d'autres tableaux annuels couvrant la période 2013 - 2020.

Remarque :La réponse d'insertion ci-dessous est "INSERT 0 0", ce qui suggère qu'elle n'a rien inséré. Cela sera abordé plus loin dans cet article.

severalnines=# INSERT INTO data_log (date, event_details) VALUES ('2018-08-20 15:22:14', 'First insert');
INSERT 0 0

severalnines=# SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |            date            | event_details
--------------+----------------------------+---------------
            1 | 2018-08-17 23:01:38.324056 | First insert
(1 row)

Il existe, mais examinons le planificateur de requêtes pour nous assurer que la ligne provient de la bonne table enfant et que la table parent n'a renvoyé aucune ligne.

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log;
                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..130.12 rows=5813 width=44) (actual time=0.016..0.019 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
   ->  Seq Scan on data_log_2015  (cost=0.00..21.30 rows=1130 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2013  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2014  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2016  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2017  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2018  (cost=0.00..1.02 rows=2 width=44) (actual time=0.005..0.005 rows=1 loops=1)
   ->  Seq Scan on data_log_2019  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
   ->  Seq Scan on data_log_2020  (cost=0.00..17.80 rows=780 width=44) (actual time=0.001..0.001 rows=0 loops=1)
 Planning time: 0.373 ms
 Execution time: 0.069 ms
(12 rows)

Bonne nouvelle, la ligne unique que nous avons insérée a atterri dans le tableau 2018, à sa place. Mais comme nous pouvons le voir, la requête ne spécifie pas de clause where en utilisant la colonne de date, donc pour tout récupérer, le planificateur de requête et l'exécution ont effectué une analyse séquentielle sur chaque table.

Ensuite, testons en utilisant une clause where.

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.013..0.014 rows=1 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.007..0.007 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.006 rows=1 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.591 ms
 Execution time: 0.041 ms
(7 rows)

Ici, nous pouvons voir que le planificateur de requêtes et l'exécution ont effectué une analyse séquentielle sur deux tables, la table parent et la table enfant pour 2018. Il existe des tables enfants pour les années 2013 à 2020, mais celles autres que 2018 n'ont jamais été consultées car la clause where a une plage appartenant uniquement à 2018. Le planificateur de requêtes a exclu toutes les autres tables car la CHECK CONSTRAINT considère qu'il est impossible que les données existent dans ces tables.

Travailler des partitions avec des outils ORM stricts ou la validation de ligne insérée

Comme mentionné précédemment, l'exemple que nous avons construit renvoie un 'INSERT 0 0' même si nous avons inséré une ligne. Si les applications qui insèrent des données dans ces tables partitionnées s'appuient sur la vérification que les lignes insérées sont correctes, elles échoueront. Il existe un correctif, mais il ajoute une autre couche de complexité à la table partitionnée, il peut donc être ignoré si ce scénario n'est pas un problème pour les applications utilisant la table partitionnée.

Utiliser une vue au lieu de la table parent.

Le correctif de ce problème consiste à créer une vue qui interroge la table parent et à diriger les instructions INSERT vers la vue. L'insertion dans une vue peut sembler folle, mais c'est là qu'intervient le déclencheur de la vue.

severalnines=# CREATE VIEW data_log_view AS 
 SELECT data_log.data_log_sid,
     data_log.date,
     data_log.event_details
    FROM data_log;
CREATE VIEW

severalnines=# ALTER VIEW data_log_view ALTER COLUMN data_log_sid SET default nextval('data_log_data_log_sid_seq'::regclass);
ALTER VIEW

L'interrogation de cette vue ressemblera à l'interrogation de la table principale, et les clauses WHERE ainsi que JOINS fonctionneront comme prévu.

Afficher la fonction spécifique et le déclencheur

Au lieu d'utiliser la fonction et le déclencheur que nous avons définis précédemment, ils seront tous deux légèrement différents. Modifications en gras.

CREATE OR REPLACE FUNCTION public.insert_trigger_view()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
BEGIN
    IF NEW.date >= '2018-01-01' AND NEW.date < '2019-01-01' THEN
        INSERT INTO part.data_log_2018 VALUES (NEW.*);
        RETURN NEW;

    ELSIF NEW.date >= '2019-01-01' AND NEW.date < '2020-01-01' THEN
        INSERT INTO part.data_log_2019 VALUES (NEW.*);
        RETURN NEW;

    END IF;
END;
$function$;

severalnines=# CREATE TRIGGER insert_trigger INSTEAD OF INSERT ON data_log_view FOR EACH ROW EXECUTE PROCEDURE insert_trigger_view();

La définition "INSTEAD OF" reprend la commande d'insertion sur la vue (qui ne fonctionnerait pas de toute façon) et exécute la fonction à la place. La fonction que nous avons définie a une exigence très spécifique de faire un 'RETURN NEW;' une fois l'insertion dans les tables enfants terminée. Sans cela (ou en le faisant comme nous l'avons fait auparavant avec 'RETURN NULL') se traduira par 'INSERT 0 0' au lieu de 'INSERT 0 1' comme on pourrait s'y attendre.

Exemple :

severalnines=# INSERT INTO data_log_view (date, event_details) VALUES ('2018-08-20 18:12:48', 'First insert on the view');
INSERT 0 1

severalnines=# EXPLAIN ANALYZE SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.03 rows=2 width=44) (actual time=0.015..0.017 rows=2 loops=1)
   ->  Seq Scan on data_log  (cost=0.00..1.00 rows=1 width=44) (actual time=0.009..0.009 rows=0 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
   ->  Seq Scan on data_log_2018  (cost=0.00..1.03 rows=1 width=44) (actual time=0.006..0.007 rows=2 loops=1)
         Filter: ((date >= '2018-08-01 00:00:00'::timestamp without time zone) AND (date < '2018-09-01 00:00:00'::timestamp without time zone))
 Planning time: 0.633 ms
 Execution time: 0.048 ms
(7 rows)

severalnines=# SELECT * FROM data_log_view WHERE date >= '2018-08-01' AND date < '2018-09-01';
 data_log_sid |        date         |      event_details
--------------+---------------------+--------------------------
            1 | 2018-08-20 15:22:14 | First insert
            2 | 2018-08-20 18:12:48 | First insert on the view
(2 rows)

Les applications testant que le « rowcount » inséré est correct trouveront que ce correctif fonctionne comme prévu. Dans cet exemple, nous avons ajouté _view à notre vue et à notre procédure stockée, mais si la table doit être partitionnée sans qu'aucun utilisateur ne sache / changement d'application, nous renommerons la table parent en data_log_parent et appellerons la vue par l'ancien nom de la table parent.

Mise à jour d'une ligne et modification de la valeur de la colonne partitionnée

Une chose à savoir est que si vous effectuez une mise à jour sur les données de la table partitionnée et que vous modifiez la valeur de la colonne en quelque chose qui n'est pas autorisé par la contrainte, une erreur se produira. Si ce type de mise à jour ne se produit jamais, il peut être ignoré, mais si c'est une possibilité, un nouveau déclencheur pour les processus UPDATE doit être écrit qui supprimera effectivement la ligne de l'ancienne partition enfant et en insèrera une nouvelle dans le nouvelle partition enfant cible.

Création de futures partitions

La création de futures partitions peut se faire de différentes manières, chacune avec ses avantages et ses inconvénients.

Futur créateur de partition

Un programme externe peut être écrit pour créer de futures partitions X fois avant qu'elles ne soient nécessaires. Dans un exemple de partitionnement partitionné à une date, la prochaine partition nécessaire à créer (dans notre cas 2019) pourrait être définie pour être créée en décembre. Il peut s'agir d'un script manuel exécuté par l'administrateur de la base de données ou configuré pour que cron l'exécute en cas de besoin. Des partitions annuelles signifieraient qu'il s'exécute une fois par an, mais les partitions quotidiennes sont courantes, et une tâche cron quotidienne rend un DBA plus heureux.

Créateur de partition automatique

Avec la puissance de plpgsql, nous pouvons capturer des erreurs si nous essayons d'insérer des données dans une partition enfant qui n'existe pas, et à la volée créer la partition nécessaire, puis réessayer d'insérer. Cette option fonctionne bien, sauf dans le cas où de nombreux clients différents insérant des données similaires en même temps pourraient provoquer une condition de concurrence où un client crée la table, tandis qu'un autre tente de créer la même table et obtient une erreur indiquant qu'elle existe déjà. Une programmation plpgsql intelligente et avancée peut résoudre ce problème, mais la question de savoir si cela vaut ou non le niveau d'effort est à débattre. Si cette condition de concurrence ne se produit pas en raison des modèles d'insertion, alors il n'y a pas de quoi s'inquiéter.

Suppression de partitions

Si les règles de conservation des données dictent que les données sont supprimées après un certain laps de temps, cela devient plus facile avec les tables partitionnées si elles sont partitionnées sur une colonne de date. Si nous devons supprimer des données datant de 10 ans, cela pourrait être aussi simple que :

severalnines=# DROP TABLE part.data_log_2007;
DROP TABLE

C'est beaucoup plus rapide et plus efficace qu'une instruction 'DELETE', car cela n'entraîne pas de tuples morts à nettoyer avec un aspirateur.

Remarque :Si vous supprimez des tables de la configuration de la partition, le code des fonctions de déclenchement doit également être modifié pour ne pas diriger la date vers la table supprimée.

Ce qu'il faut savoir avant de partitionner

Les tables de partitionnement peuvent offrir une amélioration drastique des performances, mais cela pourrait aussi les aggraver. Avant de passer aux serveurs de production, la stratégie de partitionnement doit être testée de manière approfondie, pour la cohérence des données, la vitesse des performances, tout. Le partitionnement d'une table comporte quelques pièces mobiles, elles doivent toutes être testées pour s'assurer qu'il n'y a aucun problème.

Lorsqu'il s'agit de décider du nombre de partitions, il est fortement suggéré de maintenir le nombre de tables enfants sous 1000 tables, et même plus bas si possible. Une fois que le nombre de tables enfants dépasse ~ 1000, les performances commencent à chuter car le planificateur de requête lui-même finit par prendre beaucoup plus de temps juste pour faire le plan de requête. Il n'est pas rare qu'un plan de requête prenne plusieurs secondes, alors que l'exécution réelle ne prend que quelques millisecondes. Si vous répondez à des milliers de requêtes par minute, quelques secondes peuvent immobiliser les applications.

Les procédures stockées du déclencheur plpgsql peuvent également devenir compliquées et, si elles sont trop compliquées, ralentir également les performances. La procédure stockée est exécutée une fois pour chaque ligne insérée dans la table. S'il finit par faire trop de traitement pour chaque ligne, les insertions pourraient devenir trop lentes. Les tests de performance permettront de s'assurer qu'il est toujours dans une plage acceptable.

Soyez créatif

Le partitionnement des tables dans PostgreSQL peut être aussi avancé que nécessaire. Au lieu de colonnes de date, les tableaux peuvent être partitionnés sur une colonne "pays", avec un tableau pour chaque pays. Le partitionnement peut être effectué sur plusieurs colonnes, telles qu'une colonne "date" et une colonne "pays". Cela rendra la procédure stockée gérant les insertions plus complexe, mais c'est 100 % possible.

N'oubliez pas que les objectifs du partitionnement sont de diviser des tables extrêmement volumineuses en plus petites, et de le faire de manière bien pensée pour permettre au planificateur de requêtes d'accéder aux données plus rapidement qu'il ne pourrait l'avoir dans la plus grande table d'origine.

Partitionnement déclaratif

Dans PostgreSQL 10 et versions ultérieures, une nouvelle fonctionnalité de partitionnement « Partitionnement déclaratif » a été introduite. C'est un moyen plus simple de configurer des partitions, mais il a quelques limitations. Si les limitations sont acceptables, il fonctionnera probablement plus rapidement que la configuration manuelle des partitions, mais de nombreux tests permettront de le vérifier.

La documentation officielle de postgresql contient des informations sur le partitionnement déclaratif et son fonctionnement. C'est nouveau dans PostgreSQL 10, et avec la version 11 de PostgreSQL à l'horizon au moment d'écrire ces lignes, certaines des limitations sont corrigées, mais pas toutes. Au fur et à mesure que PostgreSQL évolue, le partitionnement déclaratif peut remplacer complètement le partitionnement plus complexe couvert dans cet article. Jusque-là, le partitionnement déclaratif peut être une alternative plus simple si aucune des limitations ne limite les besoins de partitionnement.

Limites du partitionnement déclaratif

La documentation PostgreSQL traite de toutes les limitations de ce type de partitionnement dans PostgreSQL 10, mais un excellent aperçu peut être trouvé sur le Wiki officiel de PostgreSQL qui répertorie les limitations dans un format plus facile à lire, ainsi que celles qui ont été corrigées dans le prochain PostgreSQL 11.

Demandez à la communauté

Les administrateurs de bases de données du monde entier conçoivent depuis longtemps des stratégies de partitionnement avancées et personnalisées, et beaucoup d'entre nous traînent sur IRC et les listes de diffusion. Si vous avez besoin d'aide pour décider de la meilleure stratégie ou simplement pour résoudre un bogue dans une procédure stockée, la communauté est là pour vous aider.

  • IRC
    Freenode a un canal très actif appelé #postgres, où les utilisateurs s'entraident pour comprendre des concepts, corriger des erreurs ou trouver d'autres ressources.
  • Listes de diffusion
    PostgreSQL a une poignée de listes de diffusion qui peuvent être jointes. Des questions/problèmes plus longs peuvent être envoyés ici et peuvent atteindre beaucoup plus de personnes qu'IRC à tout moment. Les listes peuvent être trouvées sur le site Web de PostgreSQL, et les listes pgsql-general ou pgsql-admin sont de bonnes ressources.