Ma façon de partitionner dans PostgreSQL



Lorsque nous cessons de contrÎler la taille de la table, la maintenance et la mise à disposition des données deviennent une tùche non triviale. J'ai déjà rencontré un tel problÚme en production, il y a plus de données tous les jours, la table ne tient pas en mémoire, les serveurs répondent depuis longtemps, mais une solution a été trouvée.

Bonjour, Habr! Je m'appelle Diamond et maintenant je veux partager une méthode qui m'a aidé à implémenter le partitionnement.

Partitionnement dans PostgreSql


Le partitionnement (ou, comme ils l'appellent, le partitionnement) est le processus de division d'une grande table logique en plusieurs sections physiques plus petites. C'est ce qui nous aide à gérer nos données.

Exemple: nous avons une table «ventes», qui est divisĂ©e par un intervalle d'un mois, et ces sections peuvent ĂȘtre divisĂ©es en sous-sections encore plus petites par rĂ©gion.


Schéma «ventes» de la table partitionnée

Inconvénients de cette approche:

- Structure de base de données compliquée. Chaque section des définitions de base de données est une table, bien qu'elle fasse partie d'une entité logique.
- Vous ne pouvez pas convertir une table existante en une table partitionnée et vice versa.
- Il n'y a pas de support complet dans Postgres version 11.

Avantages:

+ Performance. Dans certains cas, nous pouvons travailler avec un ensemble limitĂ© de sections sans parcourir la table entiĂšre, mĂȘme la recherche d'index pour les grandes tables sera plus lente. Augmente la disponibilitĂ© des donnĂ©es.
+ Téléchargement en masse et suppression de données avec les commandes ATTACH / DETACH. Cela nous évite des frais généraux sous forme de vide. ce qui vous permet de maintenir plus efficacement la base de données.
+ PossibilitĂ© de spĂ©cifier TABLESPACE pour la section. Cela nous donne la possibilitĂ© de transfĂ©rer des donnĂ©es vers d'autres sections, mais nous travaillons toujours dans la mĂȘme instance et les mĂ©tadonnĂ©es du rĂ©pertoire principal contiendront des informations sur les sections (Ă  ne pas confondre avec le partitionnement).

2 façons d'implémenter le partitionnement dans PostgreSql:



1. HĂ©ritage de tables (HÉRITAGES)
Lors de la crĂ©ation d'une table, nous disons "hĂ©riter d'une autre table (parent)". Dans le mĂȘme temps, nous ajoutons des restrictions pour la gestion des donnĂ©es dans le tableau. Par cela, nous soutenons la logique de fractionnement des donnĂ©es, mais ce sont logiquement des tables diffĂ©rentes.

Il convient de noter ici l'extension développée par Postgres Professional pg_pathman, qui implémente le partitionnement, également par héritage de table.

CREATE TABLE orders_y2010 ( CHECK (log_date >= DATE '2010-01-01) ) INHERITS (orders); 

2. Approche déclarative (PARTITION)

Une table est définie comme partitionnée de maniÚre déclarative. Cette solution est apparue dans la version 10 de PostgreSql.

 CREATE TABLE orders (log_date date not null, 
) PARTITION BY RANGE(log_date); 


J'ai choisi une approche déclarative. Cela donne un gros avantage - nativité, plus de fonctionnalités sont prises en charge par le noyau. Considérez le développement de PostgreSQL dans cette direction:


Source

Mais PostgreSql continue d'évoluer et la version 12 prend en charge la liaison à une table partitionnée. C'est une grande percée.

Mon chemin


Compte tenu de ce qui précÚde, un script a été écrit en PL / pgSQL, ce qui crée une table partitionnée basée sur la table existante et «jette» tous les liens vers la nouvelle table. Ainsi, nous obtenons une table partitionnée basée sur la table existante et continuons à travailler avec elle comme avec une table standard.
Le script ne nĂ©cessite pas de dĂ©pendances supplĂ©mentaires et s'exĂ©cute dans un circuit sĂ©parĂ© qu'il crĂ©e lui-mĂȘme. Enregistre Ă©galement les actions de rĂ©tablissement et d'annulation. Ce script rĂ©sout deux tĂąches principales: crĂ©e une table partitionnĂ©e et implĂ©mente des liens externes vers celle-ci via les dĂ©clencheurs de dĂ©clenchement.

Exigence de script: PostgreSql v.:11 et supérieur.

Passons maintenant en revue le script plus en détail. L'interface est trÚs simple:
Il y a deux procédures qui font tout le travail.

1. Le principal défi - à ce stade, nous ne changeons pas le tableau principal, mais tout le nécessaire pour la coupe sera créé dans un schéma distinct:

  call partition_run(); 


2. Appelez les tùches différées qui étaient prévues pendant les travaux principaux:

  call partition_run_jobs(); 


Le travail peut ĂȘtre lancĂ© dans plusieurs threads. Le nombre optimal de threads est proche du nombre de tables partitionnĂ©es.

ParamÚtres d'entrée pour le script (enregistrement _pt)



Le script de l'intérieur, les principales actions:

- Créer une table partitionnée
  perform _partition_create_parent_table(_pt); 

- Créer des sections
  perform _partition_create_child_tables(_pt); 

- Copiez les données dans la section
  perform _partition_copy_data(_pt); 

- Ajouter des restrictions (travail)
  perform _partition_add_constraints(_pt); 

- Restaurer les liens vers des tables externes
  perform _partition_restore_referrences(_pt); 

- Restaurer les déclencheurs
  perform _partition_restore_triggers(_pt); 

- Créer un déclencheur d'événement
  perform _partition_def_tr_on_delete(_pt); 

- Créer des index (job)
  perform _partition_create_index(_pt); 

- Remplacer les vues, les liens de section (travail)
  perform _partition_replace_view(_pt); 


La durée d'exécution du script dépend de nombreux facteurs, mais les principaux sont la taille des tables cibles, le nombre de relations, les index et les caractéristiques du serveur. Dans mon cas, une table de 300 Go a été partitionnée en moins d'une heure.


RĂ©sultat


Qu'avons-nous obtenu? Regardons le plan de requĂȘte:

  EXPLAIN ANALYZE select * from “sales” where dt BETWEEN '01.01.2019'::date and '14.01.2019'::date 




Nous avons obtenu le rĂ©sultat de la table partitionnĂ©e plus rapidement et utilisĂ© moins de ressources de notre serveur par rapport Ă  la requĂȘte vers une table rĂ©guliĂšre.

Dans cet exemple, les tables rĂ©guliĂšres et partitionnĂ©es sont sur la mĂȘme base et ont environ 200 millions d'enregistrements. C'est un bon rĂ©sultat, Ă©tant donnĂ© que nous avons, sans rĂ©Ă©crire le code de l'application, accĂ©lĂ©rĂ©. Les requĂȘtes sur d'autres index fonctionnent Ă©galement bien, mais n'oubliez pas: chaque fois que nous pouvons dĂ©terminer une section, le rĂ©sultat sera plusieurs fois plus rapide, car PostgreSql peut supprimer des sections supplĂ©mentaires au stade de la planification de la demande ( dĂ©finissez enable_partition_pruning sur on ).

Résumé


J'ai rĂ©ussi Ă  implĂ©menter le partitionnement sur des tables qui ont de nombreuses relations et Ă  assurer l'intĂ©gritĂ© de la base de donnĂ©es. Le script est indĂ©pendant de structures de donnĂ©es spĂ©cifiques et peut ĂȘtre rĂ©utilisĂ©.

PostgreSQL est la base de données relationnelle open source la plus avancée au monde!

Merci Ă  tous!

Lien vers la source

Source: https://habr.com/ru/post/fr481694/


All Articles