web-dev-qa-db-fra.com

Utilisation du héritage de la table au lieu de tables de cartographie

Cela semble être un scénario assez commun: plusieurs types qui composent tous le même type d'enfant.

Cela pourrait généralement ressembler à:

-- 'name' is unique per parent record
CREATE TABLE sometype (
  sometype_id serial PRIMARY KEY,
  name        text
);

CREATE TABLE foo (foo_id serial PK);
CREATE TABLE bar (bar_id serial PK);

CREATE TABLE foo_sometype (
  foo_id      int4,
  sometype_id int4
);

CREATE TABLE bar_sometype (
  bar_id      int4,
  sometype_id int4
);

Ce qui va bien, mais encombrant d'interroger. Je pense que cela pourrait être plus propre:

-- 'name' is unique per parent record
CREATE TABLE sometype (
  name        text
);

CREATE TABLE foo_sometype (
  foo_id      int4
) INHERITS(sometype);

CREATE TABLE bar_sometype (
  bar_id      int4,
) INHERITS(sometype);

Ce que j'aime à propos de ceci:

  • simple à rejoindre (avec USING)
  • pas besoin d'ajouter une clé de substitution à "Attachyty", c'est explicitement une composante de "foo" et "bar"

Semble comme une utilisation atypique de l'héritage, cependant.

Toute raison non de faire cela?


[.____] sur les "déficiences" de l'héritage

Notez que les mises en garde standard du héritage PG ne sont pertinentes que lorsque l'héritage de la table est utilisée pour modéliser directement le héritage de classe, ce qui n'est pas ce que je fais ici. En fait, pour que cela fonctionne, je a besoin héritage pour se comporter comme ça.

Je souhaite presque qu'ils l'appelaient autre chose que "héritage", car le comportement est assez logique et que les "lacunes" ne sont pertinentes que pour une seule case.


[.____] avantages sur la structure de table dupliquée manuellement

Comme Evan souligne, je pouvais simplement créer manuellement "foo_someType" et "bar_someType" qui ressemblent exactement à ce que je décris, mais je pense qu'il y a quelques avantages significatifs à la structure héritée:

  • La relation héritée définit explicitement "FOO_SOMETYPE" et "bar_someType" comme étant du même type , pas seulement deux tables qui ont les mêmes colonnes.
  • Faire des changements de schéma futurs à travers la table des parents diminue les chances de divergence accidentelle (avec un peu de travail, cela pourrait en réalité être appliqué).
  • Plus important encore, le code du client peut être généré contre la table des parents et s'appliquait aux enfants avec seulement une modification du nom de la table, avec (à nouveau) la confiance que la structure de la table est appliquée.

Ainsi, comme exemple de manière artificielle, FOO et Bar pourraient avoir un trait de hassometypeliste, qui résoudra toutes les opérations "Atorstales" et sait que les deux tables peuvent être mappées sur la classe de Sentaype.

Représentant la relation FOO/BAR, qu'il soit modélisé comme un trait ou comme héritage, est l'objectif ultime ici.

Incidemment, à l'utilisateur naïf/Query-Writer - qui ne devrait pas faire de changements de schéma - ces deux manières auront la même chose.

5
Dmitri

L'héritage est l'une de ces caractéristiques que je ne toucherais pas. Afaik, il est utilisé à l'intérieur de la réplication et partitionnement à une certaine capacité. Je ne sais pas si c'était même conçu avec l'intention d'être utilisé par l'utilisateur final.

Incordements techniques concrets

Inconvénients sur une unique et des références

Les documents couvrent certains des inconvénients de la section de mise en garde (ci-dessous est important).

  • Si nous avons déclaré parent.name d'être unique ou une clé primaire, cela n'arrêterait pas la table enfant d'avoir des lignes avec des noms de duplication des lignes du parent. Et ces lignes en double seraient par défaut apparaissent dans des requêtes de parent. En fait, par enfant par défaut n'aurait aucune contrainte unique du tout, et pourrait donc contenir plusieurs rangées avec le même nom. Vous pouvez ajouter une contrainte unique à l'enfant, mais cela n'empêcherait pas la duplication comparée au parent.
  • De même, si nous devions spécifier que le parent.name fait référence à une autre table, cette contrainte ne se propagerait pas automatiquement à l'enfant. Dans ce cas, vous pourriez y travailler en ajoutant manuellement la même contrainte de référence à l'enfant.
  • Spécificant que les références de colonne d'une autre table (nom) permettraient à l'autre table de contenir des noms parents, mais pas des noms d'enfants. Il n'y a pas de bonne solution de contournement pour ce cas.

Lent de progrès développant des hérités

Ces lacunes ont été mentionnées pour la première fois dans les documents à 7,3 publiés en 1996 bien qu'ils existaient depuis la mise en œuvre de l'héritage.

Cette déficience sera probablement corrigée dans une nouvelle version future.

Et le seul changement consistait à rendre les déficiences plus explicites et verbeuses dans les documents à 8,0 publiés en 2010.

Ces lacunes seront probablement fixées dans une nouvelle version future, mais dans l'intervalle de soins considérables sont nécessaires pour décider si l'héritage est utile pour votre problème.

Bonne chance en attente de cela une nouvelle version future . Et certaines des choses que vous parlez de ne sont tout simplement pas uniques à la composition,

Sauver une "clé" est discutable

  • aucune clé de substitution sur 'Mémentarière', c'est explicitement une composition

Comment est-ce différent de la fabrication de sometype une liste d'attributs et de se connecter directement à celui-ci?

CREATE TABLE sometype (sometype_name text PRIMARY KEY);
CREATE TABLE foo (foo_id serial PRIMARY KEY);
CREATE TABLE foo_sometype (
  foo_id int REFERENCES foo,
  sometype_name text REFERENCES sometype,
  PRIMARY KEY ( foo_id, sometype_name )
);

Maintenant, vous n'avez même pas à rejoindre foo_sometype à sometype pour obtenir sometype.sometype_name.

Cloison de table

Tous ces problèmes de côté, cela devient encore pire avec le prochain PostgreSQL 10 version de la partition de table

L'héritage multiple n'est pas autorisé, et la partition et l'héritage ne peuvent pas être mélangés

Vous voulez donc héritage? Forgo partitionnement, qui a en réalité des avantages en planificateur réel.

MODIFIER TABLE

Hélas, ALTER TABLE a aussi quelques inconvénients énumérés dans ses notes également,

Si une table présente des tables de descendance, il n'est pas autorisé à ajouter, à renommer ou à modifier le type de colonne ou à renommer une contrainte héritée dans la table des parents sans faire de même pour les descendants. C'est-à-dire que Alter Tableau uniquement sera rejeté. Cela garantit que les descendants ont toujours des colonnes correspondant au parent. [...] Une opération de colonne de chute récursive supprimera une colonne de table descendante uniquement si le descendant n'hérite pas de cette colonne d'autres parents et n'a jamais eu de définition indépendante de la colonne. Une colonne de chute non cumulative (c'est-à-dire une colonne de dépose (c'est-à-dire une table d'altération), mais la marque de manière indépendante plutôt que héritée. [...] la gâchette, le cluster, le propriétaire et les actions de l'espace de table ne se recueillent jamais à des tables descendantes; C'est-à-dire qu'ils agissent toujours comme si seulement ont été spécifiés. L'ajout d'une contrainte ne recouvre que pour les contraintes de vérification qui ne sont pas marquées sans hériter.

Conclusion

Je ne pense pas que beaucoup de gens utilisent l'héritage. Je ne l'ai jamais vu à l'état sauvage. L'héritage dans la DB ajoute à la courbe d'apprentissage et certaines caractéristiques sont tout simplement mieux laissées seules. Vous n'avez pas à trouver une demande pour eux.

Vous trouverez peut-être ce message sur la pile débordement utile, "quand utiliser des tables héritées dans PostgreSQL?".

8
Evan Carroll

Les lacunes mentionnées ne sont pas une raison pour ne pas utiliser l'héritage! Héritage fonctionne ici similaire à la classe-héritage avec des objets indépendants. Vous pouvez avoir une classe/table 'fruits' et une classe/table 'pommes' et des "oranges". Étant donné que les pommes et les oranges héritent de leurs méta définitions de fruits, vous pouvez les récupérer via des fruits. Cependant, ce sont des classes indépendantes, avec une énumération indépendante et que vous pouvez vous attendre d'autre ....

Si vous avez vraiment besoin de prévenir les collisions: définissez une gâchette ou une clé chèque/étrangère sur la table principale (sans in).

Mais s'il vous plaît, juste parce que vous êtes insatisfait de la façon dont les œuvres d'héritage dans PostgreSQL - ne découragent pas les gens de l'utiliser! Les sous-classes ou tables indépendantes sont merveilleuses! Et si vous avez besoin d'une dépendance - impliquez-la comme vous en avez besoin. Il existe de nombreux bons tutoriels, y compris la documentation officielle. Voici un autre exemple: Héritage - une raison de plus d'aimer PostgreSQL .

J'utilise également l'héritage dans l'un de mes projets, malgré les collisions de clés primaires possibles (ma table des parents n'a pas de clés principales définies et que mon modèle ne l'exige pas).

Il existe également des moyens d'utiliser l'héritage pour améliorer les performances, non seulement l'ORM.

Difficile n'est pas la même chose que mal.

4
Mihail Gershkovich

De nombreuses raisons d'éviter, et tous bouillir pour violer les principes du modèle relationnel. Plus évidemment, les tables enfants sont des sacs, non des relations et le manque de clés étrangères violent le principe d'information, ce qui nécessite que toutes les informations soient sous forme de valeurs d'attribut dans les tuples.

Les plus grandes conséquences protégrées sont la perte d'intégrité de l'identité dans les tables d'enfants (des doublons ont un moyen d'être inséré lorsque vous vous attendez le moins) et la perte de transparence dans le modèle: vous regrettez gravement lorsque vous devez expliquer cela au prochain utilisateur de la Modèle, et non, vous ne pouvez jamais être sûr que vous serez l'utilisateur unique de la vie.

En ce qui concerne la construction relationnelle (avec des clés étrangères) étant encombrant à interroger, ce n'est pas le cas. Premièrement, on peut toujours créer des vues (relations dérivées); Et deuxièmement, il est préférable que l'utilisateur comprenne ce qu'il interroge de toute façon, que des comportements automagiques.

2
Leandro