¿Debo evitar de todos modos la herencia de mesas múltiples (concretas) en Django?

Muchos desarrolladores experimentados recomiendan no usar la herencia de mesas múltiples de Django debido a su bajo rendimiento:

  1. Django gotcha: herencia concreta de Jacob Kaplan-Moss , un colaborador principal de Django.

    En casi todos los casos, la herencia abstracta es un mejor enfoque a largo plazo. He visto más de unos pocos sitios aplastados por la carga introducida por la herencia concreta, por lo que sugiero encarecidamente a los usuarios de Django que aborden cualquier uso de herencia concreta con una gran dosis de escepticismo.

  2. Dos paladas de Django por Daniel Greenfield ( @pydanny )

    La herencia de múltiples tablas, a veces llamada “herencia concreta”, es considerada por los autores y muchos otros desarrolladores como algo malo. Recomendamos encarecidamente no usarlo.

    A toda costa, todos deberían evitar la herencia de tablas múltiples, ya que agrega confusión y gastos generales considerables. En lugar de la herencia de múltiples tablas, use OneToOneFields y ForeignKeys explícitos entre los modelos para que pueda controlar cuándo se cruzan las uniones.

Pero sin la herencia de múltiples tablas, no puedo fácilmente

  1. Modelo base de referencia en otro modelo (tiene que usar GenericForeignKey o dependencia inversa);

  2. Obtenga todas las instancias del modelo base .

    (Siéntase libre de agregar más)

Entonces, ¿qué hay de malo con este tipo de herencia en Django? ¿Por qué son mejores OneToOneFields explícitos?

¿Cuánto sufre el rendimiento de JOINs? ¿Hay puntos de referencia que muestran la diferencia en el rendimiento?

¿No select_related() nos permite controlar cuándo se invoca JOIN?


He trasladado ejemplos concretos a una pregunta por separado, ya que esta es demasiado amplia, y he añadido una lista de razones para usar la herencia de varias tablas en su lugar.

En primer lugar, la herencia no tiene una traducción natural a la architecture de bases de datos relacionales (bueno, lo sé, Oracle Type Objects y alguna otra herencia de soporte RDBMS, pero django no aprovecha esta funcionalidad)

En este punto, note que django genera nuevas tablas en subclases y escribe muchas left joins a la left joins para recuperar datos de estas ‘sub-tablas’ . Y las uniones izquierdas no son tus amigos . En un escenario de alto rendimiento, como un back-end de juego u otra cosa, debe evitarlo y resolver la herencia “a mano” con algunos artefactos como nulos, OneToOne o claves externas. En el escenario OneToOne , puede llamar directamente a la tabla relacionada o solo si la necesita.

… PERO …

“En mi opinión (TGW)” , debe incluir la herencia del modelo en sus proyectos empresariales cuando capte su universo de discurso . Hago esto y ahorro muchas horas de desarrollo a mis clientes gracias a esta característica. Además, el código se vuelve limpio y elegante y eso significa un fácil mantenimiento (aviso que este tipo de proyectos no tienen cientos o solicitudes por segundo)

Pregunta por pregunta

P: ¿Qué hay de malo con este tipo de herencia en Django?
A: Muchas mesas, muchas combinaciones a la izquierda.

P: ¿Por qué son mejores OneToOneFields explícitos?
R: Puede acceder directamente al modelo relacionado sin combinaciones izquierdas.

P: ¿Hay algún ejemplo ilustrativo (puntos de referencia)?
A: No comparable.

P: ¿No select_related () nos permite controlar cuándo se invoca JOIN?
R: django se une a las tablas necesarias.

P: ¿Cuáles son las alternativas a la herencia de tablas múltiples cuando necesito hacer referencia a una clase base en otro modelo?
A: anulación. Relaciones OneToOne y muchas líneas de código. Depende de las necesidades de la aplicación.

P: ¿GenericForeignKeys es mejor en este caso?
A: No para mí.

P: ¿Qué sucede si necesito OneToOneField para el modelo base? A: Escribirlo. No hay problema con esto Por ejemplo, puede extender el modelo de usuario y también puede tener un modelo base de OneToOne a usuario para algunos usuarios.

Conclusión

Debe saber el costo del código de escritura y mantenimiento sin herencia del modelo y también el costo del hardware para admitir las aplicaciones de herencia del modelo y actuar en consecuencia.

Por lo que entiendo, está utilizando OneToOneField en RelatedModel para BaseModel porque, en última instancia, desea un enlace de uno a uno entre RelatedModel y cada Submodel1 a Submodel9 . Si es así, hay una forma más eficiente de hacerlo sin herencia de tablas múltiples ni relaciones genéricas.

Solo deshazte del BaseModel y en cada SubmodelX , ten un OneToOneField para 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() 

Esto le permitiría acceder a SubmodelX desde una instancia de RelatedModel utilizando un campo llamado the_thing , al igual que en el ejemplo de herencia multi-tabla que dio primero.

Tenga en cuenta que puede usar herencia abstracta para factorizar el campo related_model y cualquier otro campo común entre SubModel1 y Submodel9 .

La razón por la que usar herencia de tablas múltiples es ineficiente es porque genera una tabla adicional para el modelo base y, por lo tanto, JOIN adicionales para acceder a esos campos. El uso de relaciones genéricas sería más eficiente si más adelante descubre que necesita un campo ForeignKey de RelatedModel para cada SubmodelX . Sin embargo, Django no admite relaciones genéricas en select_related() y es posible que tengas que terminar creando tus propias consultas para hacerlo de manera eficiente. El equilibrio entre el rendimiento y la facilidad de encoding depende de usted en cuanto a la cantidad de carga que espera en el servidor y la cantidad de tiempo que desea optimizar.

El mundo ha cambiado

Lo primero a tener en cuenta es que el artículo titulado Django gotcha: herencia concreta tenía casi cuatro años en el momento en que se hizo esta pregunta; en 2014. Tanto los sistemas Django como los RDBM han recorrido un largo camino desde entonces (por ejemplo, las versiones ampliamente utilizadas eran mysql 5.0 o 5.1 y la disponibilidad general en 5.5 aún faltaba un mes).

Se une a mi izquierda, se une a mi derecha

Es cierto que la herencia de tablas múltiples resulta en combinaciones extra detrás de las escenas la mayor parte del tiempo . Pero las uniones no son malvadas. Vale la pena señalar que en una base de datos correctamente normalizada, casi siempre tiene que unirse para obtener todos los datos requeridos. Cuando se usan los índices adecuados, las uniones no incluyen ninguna penalización significativa en el rendimiento.

INNER JOIN vs LEFT OUTER JOIN

Este es el caso contra la herencia de tablas múltiples, con otros enfoques es posible evitar una costosa UNIÓN EXTREMA IZQUIERDA y hacer una UNIÓN INTERNA en lugar de una subconsulta. Pero con la herencia de mesas múltiples se te niega esa elección

Django implementa la herencia de tablas múltiples a través de OneToOneField creado automáticamente como dice su documento. Por lo tanto, o bien uso de herencia abstracta o no creo que el uso de OneToOneFields explícito o ForeignKeys haga cualquier diferencia.

Intereting Posts