Pour partitionner ou ne pas partitionner?

8

Ayant déjà lu plusieurs questions sur SO, les articles de blog externes et le manuel

Je me demande toujours si je dois ou non opter pour le partitionnement.

Le cas - simplifié

Stockage des données client. Tous les noms des tableaux mentionnés ci-dessous sont faits pour plus de clarté.

  1. Avoir des objets identifiables par le client et des êtres non physiques, ainsi que leurs objets physiques dans lesquels ils sont réellement stockés en cas de besoin de renvoyer certains objets au client à la demande, ou de les traiter d'une autre manière. Ils sont cartographiés dans une relation plusieurs-à-plusieurs. objects_nonphysical, objects_physical, objects_mapping_table.

  2. La deuxième relation plusieurs-à-plusieurs se situe entre ces objets non physiques et leurs mesures. Certains objets sont liés à certaines métriques. metrics,metrics_objects_nonphysical

  3. Les objets non physiques et physiques ont leurs tables de hiérarchie qui sont des relations enfant-parent. objects_nonphysical_hierarchy,objects_physical_hierarchy

Selon les besoins et les exigences de chaque client, les données sur les objets physiques peuvent être fournies ou peuvent devoir être créées à partir de zéro. Fondamentalement, ce que je dois faire, c'est:

  • Maintenir le système interne pour les déclarations rapides INSERTet SELECT, car c'est ici que le mappage va avoir lieu.

  • Maintenir le système pour que le client externe puisse visualiser et opérer sur ses objets non physiques - récupération rapide des données. Fort besoin d'efficacité pour les SELECTrelevés - ces données sont disponibles pour de nombreux clients à rechercher quand ils le souhaitent.

Ma considération

Il peut y avoir un client, qui peut accéder aux données, les visualiser et les exploiter, mais cela n'a pas besoin d'être un entrepreneur pour lequel nous avons obtenu les données de / traitons les données pour.

Cela m'a amené à introduire le partitionnement de table dans mon système, étant donné que je sais toujours dans quelles données de partition doit tomber ( partitionnement pour les sous-traitants ), puis à maintenir le système pour le client externe là où j'ai besoin de partitionner pour les clients (cela se ferait avec certains retarder l'utilisation d'outils d'automatisation et d'un ensemble de règles pour réécrire les données à la manière des clients, de sorte que pour chaque client, nous n'analysions qu'une seule partition pour chaque table.

Volume de données

Mes données vont croître constamment, en particulier lors de l'importation d'objets et de métriques de nouveaux clients. Le rythme des nouvelles données arrivant dans le système est actuellement imprévisible à long terme. Il n'y a vraiment aucun moyen de le mesurer sans savoir qui sera le prochain client. À l'heure actuelle, il n'y a que 2 clients avec plus ou moins 1 million de lignes pour chaque client dans chaque table. Mais à l'avenir, je prédis que de nouveaux clients viendront avec un volume de 10 millions de lignes environ.

Des questions

Ces questions sont toutes liées les unes aux autres.

  1. Le partitionnement doit-il vraiment être considéré ici, ou est-ce une exagération? Je le considère utile car je scanne toujours exactement une partition.
  2. Si le partitionnement est la voie à suivre, comment puis-je appliquer la FKcontrainte le plus efficacement compte tenu de mes besoins? Dois-je opter pour constraint triggers, ou simplement le conserver dans la couche application pour le système interne, ou peut-être une autre méthode?
  3. Si le partitionnement n'est pas la voie à suivre, dans quoi dois-je plonger?

S'il n'y a pas suffisamment de données fournies, veuillez me le faire savoir dans les commentaires ci-dessous.

Kamil Gosciminski
la source
3
En général, il est recommandé de démarrer la production sans frais généraux d'index, de partitions, etc., puis si nécessaire, d'ajouter des index et des partitions, etc.
alonk
1
Avec le partitionnement, vous n'obtiendrez que des accélérations sur certains types de requêtes tout en prenant un coup sur d'autres types de requêtes. Vous prendrez également un coup sur les écritures. Le partitionnement ne devrait pas être la première chose que vous atteignez, et je pense que vous serez bien en utilisant des index simples dans un avenir prévisible, et traversez ces ponts lorsque vous y arriverez. 5 millions de lignes ne sont pas si grandes. Cela pourrait être un blog utile avec des comparaisons de vitesse: if-not-true-then-false.com/2009/…
dizzystar
2
Je suis d'accord avec Dizzystar, ça ne me dérangerait pas pour le moment. Traversez ce pont si vous l'atteignez. Actuellement, le partitionnement dans Postgres rend difficile (voire impossible) l'utilisation de clés étrangères appropriées (cela pourrait changer avec 9.7 mais rien n'est encore réglé). Même une table de 50 millions de lignes n'est pas nécessairement candidate au partitionnement. Si vous avez principalement des conditions d'égalité dans vos requêtes qui réduisent le nombre de lignes substantiellement, une bonne indexation peut vous obtenir une longue route.
a_horse_with_no_name
1
Pour moi, ce que vous entendez par «partitionnement pour les entrepreneurs» n'est pas vraiment clair. Les tables utilisées par les entrepreneurs sont-elles différentes de celles qui appartiennent à un client? Est-il arrivé que le client A doive accéder aux données du client B? Si ce n'est pas le cas, la séparation des données spécifiques au client dans un schéma par client peut être un moyen de procéder - mais pas nécessairement pour les performances, mais pour la séparation des préoccupations (sécurité / confidentialité accrue, etc.).
dezso

Réponses:

1

Il y a de nombreuses questions ouvertes dans votre question, mais le partitionnement par client pourrait être la voie à suivre - surtout si:

  • vous attendez de nombreux clients,
  • chacun d'eux pourrait avoir des tonnes de données ("tonnes" signifie beaucoup plus que la taille du cache RAM),
  • la plupart de leurs ensembles de données seront mutuellement exclusifs (chaque client voit un sous-ensemble différent de données).

Les règles ou les déclencheurs sont une surcharge de performances et peuvent être évités.

Considérez quelque chose dans ce sens:

BEGIN;

CREATE USER tenant1;
CREATE USER tenant2;

CREATE SCHEMA app;
CREATE SCHEMA tenant1;
CREATE SCHEMA tenant2;

CREATE TABLE app.objects_nonphysical(id int);
CREATE TABLE app.objects_physical(id int);
CREATE TABLE app.objects_mapping(id int);    
CREATE TABLE tenant1.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant1.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant1.objects_mapping() INHERITS(app.objects_mapping);
CREATE TABLE tenant2.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant2.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant2.objects_mapping() INHERITS(app.objects_mapping);

GRANT USAGE ON SCHEMA tenant1 TO tenant1;
GRANT USAGE ON SCHEMA tenant2 TO tenant2;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant1 TO tenant1;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant2 TO tenant2;

/* TEST: simulate login as customer */
SET SESSION AUTHORIZATION tenant2;
/* No schema needed - default search_path works */
SELECT count(*) FROM objects_nonphysical; 

ROLLBACK;

Vous n'avez pas besoin de déclencheurs / règles pour le maintenir.

Il y a des extrémités ouvertes ici - ce n'est qu'un brouillon ... Quelques problèmes:

  • PK, FK et les index ne sont pas "hérités".
  • même si vous les créez, le PK n'est pas appliqué sur la table principale
  • vous pouvez surmonter cela en utilisant la même séquence pour tous les locataires
  • évidemment, l'application doit être ajustée pour ce modèle
filiprem
la source
0

Cela ne fera pas de mal si vous implémentez le partitionnement maintenant, mais utilisez une seule partition jusqu'à ce que votre système en ait vraiment besoin d'une nouvelle. En termes de performances, il n'y aura qu'une minuscule surcharge pour gérer les clés primaires et autres.

Je recommande d'utiliser des règles pour rediriger les insertions et une table externe pour les clés primaires (par exemple CREATE TABLE objects_physical_ids (id bigserial NOT NULL PRIMARY KEY), avec un déclencheur de fonction qui insère une ligne dans la table ids et la copie dans NEW.id (par exemple INSERT INTO objects_physical_ids DEFAULT VALUES RETURNING id INTO NEW.id;), et d'autres déclencheurs qui traitent de la suppression et les mises à jour, et un déclencheur exécutant ces déclencheurs de fonction pour chaque table héritée (n'oubliez pas de le faire lorsque vous créez une nouvelle table héritée!). Ensuite, toutes les tables associées peuvent avoir un FOREIGN KEYà la table ids appropriée (y compris toutes les actions de clé étrangère comme ON UPDATEou ON DELETE).

Ziggy Crueltyfree Zeitgeister
la source
2
Les règles et les déclencheurs ont certainement des frais généraux, et c'est facile à mesurer. De plus, ils ajoutent de la complexité et rendent le débogage (beaucoup) plus difficile. De plus, après être descendu plusieurs fois de cette façon, je suggérerais (sans en connaître tous les détails) de conserver une table parent vide et une ou plusieurs partitions enfants. Lorsque vous modifiez le schéma de partitionnement, cela peut s'avérer très utile.
dezso