Dois-je éviter l'héritage multi-tables (concret) à Django par tous les moyens?

de nombreux développeurs expérimentés recommandent de ne pas utiliser héritage multi-tables de Django en raison de ses mauvaises performances:

  1. Django gotcha: héritage concret par Jacob Kaplan-Moss , un des principaux contributeurs de Django.

    dans presque tous les cas, l'héritage abstrait est une meilleure approche pour le long terme. J'ai vu plus de que peu de sites écrasés sous la charge introduit par l'héritage concret, donc je suggère fortement que Les utilisateurs de Django approchent toute utilisation de l'héritage concret avec un grand une dose de scepticisme.

  2. deux Scoops de Django by Daniel Greenfield ( @pydanny )

    multi-table héritage, parfois appelé " béton l'héritage," est considéré par les auteurs et de nombreux autres développeurs d'être une mauvaise chose. Nous vous déconseillons fortement de l'utiliser.

    à tout prix, tout le monde devrait éviter l'héritage multi-table puisqu'il ajoute à la fois la confusion et les frais généraux importants. Au lieu d'un héritage multi-tables, utilisez des Champs onetoonefields explicites et Etrangers entre les modèles pour que vous puissiez contrôler quand les jointures sont traverser.

Mais sans héritage Multi-table, Je ne peux pas facilement

  1. modèle de base de référence dans un autre modèle (doivent utiliser la Dépendancegénérale ou inversée);

  2. Obtenir toutes les instances du modèle de base .

    (n'hésitez pas à en ajouter plus)

Alors, quel est le problème avec ce genre de L'héritage à Django? Pourquoi est-ce que les OneToOneFields explicites sont mieux?

A quel point la performance souffre-t-elle des jointures? Y a-t-il des points de repère qui montrent la différence dans le rendement?

est-ce que select_related() ne nous permet pas de contrôler quand les jointures sont invoquées?


j'ai déplacé des exemples concrets vers une question séparée car celle-ci devient trop large, et a ajouté une liste de raisons pour utiliser Multi-table héritage à la place.

30
demandé sur Community 2014-05-05 10:55:36

4 réponses

tout D'abord, héritage n'a pas une traduction naturelle à l'architecture de base de données relationnelle (ok, je sais, Oracle Type objets et certains autres RDBMS héritage de soutien mais django ne tirent pas avantage de cette fonctionnalité)

à ce point, noter que django génère de nouveaux tableaux pour les sous-classes et écrire lots de left joins pour extraire des données de ce 'sous-tableaux' . Et joins gauche ne sont pas vos amis . Dans un scénario de haute performance, comme un backend de jeu ou quelque chose d'autre, vous devriez l'éviter et résoudre l'héritage "à la main" avec certains artifices comme nulls, OneToOne ou des clés étrangères. Dans le scénario OneToOne , vous pouvez appeler la table liée directement ou seulement si vous en avez besoin.

... MAIS. ..

"À mon avis (TGW)" vous devez inclure l'héritage de modèle dans vos projets d'entreprise quand il attraper à votre univers du discours . Je le fais et j'ai économiser beaucoup d'heures de développement pour mes clients grâce à cette fonction. Aussi code devient propre et élégant et cela signifie entretien facile (avis que ce genre de projets n'ont pas des centaines ou des demandes par seconde)

Question par question

Q: Qu'est-ce qui ne va pas avec ce genre d'héritage à Django?

A: beaucoup de tables, beaucoup de gauche se joint.

Q: Pourquoi l'onetoonefields explicite est-il meilleur?

R: Vous pouvez accéder directement au modèle associé sans jointures de gauche.

Q: y a-t-il des exemples (benchmarks)?

R: Non comparables.

Q: N'est pas select_related () permet de contrôler quand les jointures sont invoquées?

A: django rejoint les tables nécessaires.

Q: Quelles sont les alternatives à l'héritage multi-tables lorsque je dois faire référence à une classe de base dans un autre modèle?

Un: L'Annulation. OneToOne de relations et beaucoup de lignes de code. Cela dépend des besoins d'application.

Q: Les "GenericForeignKeys" sont-ils meilleurs dans ce cas?

R: Non, pour les je.

Q: Que faire si j'ai besoin d'un champ sur le modèle de base? Un: l'Écrire. Il n'y a pas de problème avec cela. Par exemple, vous pouvez étendre le modèle D'Utilisateur et aussi vous pouvez avoir un modèle de base OneToOne to User pour certains utilisateurs.

Conclusion

vous devriez savoir le coût de code d'écriture et de maintenance sans héritage de modèle aussi le coût du matériel pour soutenir les applications d'héritage de modèle et d'agir en conséquence.

19
répondu dani herrera 2017-05-23 11:54:10

D'après ce que j'ai compris, vous utilisez OneToOneField sur le RelatedModel au BaseModel parce que finalement, vous voulez un lien un-à-un entre RelatedModel et chaque Submodel1 à Submodel9 . Si c'est le cas, il y a une façon plus efficace de le faire sans héritage multi-tables ni relations génériques.

il suffit de se débarrasser du BaseModel et dans chaque SubmodelX , avoir un OneToOneField à RelatedModel

class Submodel1(models.Model):
    related_model = models.OneToOneField(RelatedModel, null=True, blank=True, related_name='the_thing')
    some_field = models.TextField()

# ...

class Submodel9(models.Model):
    related_model = models.OneToOneField(RelatedModel, null=True, blank=True, related_name='the_thing')
    another_field = models.TextField()

Cela vous permettrait d'accéder à SubmodelX à partir d'une instance de RelatedModel en utilisant un champ nommé the_thing , tout comme dans l'exemple d'héritage multi-tables que vous avez donné pour la première fois.

notez que vous pouvez utiliser l'héritage abstrait pour exclure le champ related_model et tout autre champ commun entre SubModel1 à Submodel9 .

la raison d'utiliser l'héritage multi-tables est inefficace est parce qu'il génère une table supplémentaire pour la base modèle, et donc des jointures supplémentaires pour accéder à ces champs. Utiliser des relations génériques serait plus efficace si vous trouvez plus tard que vous avez besoin d'un champ ForeignKey de RelatedModel à chaque SubmodelX . Cependant, Django ne supporte pas les relations génériques dans select_related() et vous pourriez avoir à construire vos propres requêtes pour le faire efficacement. Le compromis entre la performance et la facilité de codage dépend de vous en fonction de combien de charge vous attendez sur le serveur et combien de temps vous vouloir dépenser l'optimisation.

10
répondu user193130 2014-05-08 16:48:29

Le monde a changé.

la première chose à noter est que l'article intitulé Django gotcha: héritage concret avait près de quatre ans au moment où cette question a été posée; en 2014. Les deux systèmes Django et RDBMs ont parcouru un long chemin depuis (par exemple mysql 5.0 ou 5.1 étaient les versions largement utilisées et 5.5 disponibilité générale était encore un mois loin).

se Joint à ma gauche, se joint à ma droite

il est vrai que l'héritage multi-table ne résulte pas en jointures supplémentaires dans les coulisses la plupart du temps . Mais les jointures ne sont pas mal. Il est intéressant de noter que dans une base de données correctement normalisée, vous devez presque toujours joindre pour récupérer toutes les données requises. Lorsque des index appropriés sont utilisés, les jointures ne comportent pas de pénalité de performance significative.

joint intérieur vs joint extérieur gauche

C'est en effet le cas contre héritage multi-table, avec d'autres approches, il est possible d'éviter une jointure externe gauche coûteuse et de faire une jointure interne à la place ou peut-être un subquery. Mais avec l'héritage multi-table vous êtes nié que le choix

5
répondu e4c5 2017-12-19 01:20:42

Django implémente un héritage multi-tables via un OneToOneField créé automatiquement comme le dit son docs.Donc, soit utiliser l'héritage abstrait ou Je ne pense pas que l'utilisation d'un onetoonefields explicite ou des ForeignKeys fait des différences.

0
répondu youngjack 2018-08-02 01:22:00