Czy powinienem unikać dziedziczenia multi-table (concrete) w Django w jakikolwiek sposób?

Wielu doświadczonych programistów zaleca używanie dziedziczenie wielu tabel Django ze względu na jego słabą wydajność:

  1. Django gotcha: concrete inheritance by Jacob Kaplan-Moss, główny współtwórca Django.

    W prawie każdym przypadku dziedziczenie abstrakcyjne jest lepszym podejściem do na dłuższą metę. Widziałem więcej niż kilka miejsc zgniecionych pod obciążeniem wprowadzone przez konkretne dziedziczenie, więc zdecydowanie sugeruję, że Użytkownicy Django podchodzą do każdego zastosowania konkretnego dziedziczenia z dużą dawka sceptycyzmu.

  2. Dwie miarki Django by Daniel Greenfield (@pydanny )

    Dziedziczenie wielostolikowe, zwane czasem "dziedziczeniem betonowym", jest uważany przez autorów i wielu innych programistów za złą rzecz. Zdecydowanie zalecamy używanie go.

    Za wszelką cenę, każdy powinien unikać dziedziczenia wielostolikowego ponieważ to dodaje zarówno zamieszania, jak i znacznych kosztów. Zamiast dziedziczenia wielostolikowego, użyj jawnych pól OneToOneFields i Obcojęzycznych pomiędzy modelami, dzięki czemu można kontrolować, kiedy połączenia są / align = "left" /

Ale bez dziedziczenia wielu tabel, nie mogę łatwo

  1. Bazowy model odniesienia w innym modelu (trzeba użyć GenericForeignKey lub odwrotnej zależności);

  2. Get all instances of base model .

    (zapraszam do dodaj więcej)

Więc co jest nie tak z tego rodzaju dziedziczeniem w Django? Dlaczego explicit OneToOneFields jest lepszy?

Jak bardzo wydajność cierpi na połączenia? Czy są jakieś benchmarki, które pokazują różnicę w wydajności?

czy select_related() nie pozwala nam kontrolować, kiedy wywoływane są połączenia?


Przeniosłem konkretne przykłady na osobne pytanie ponieważ to staje się zbyt szerokie i dodałem listę powodów dla zamiast tego używa dziedziczenia wielostolikowego.

Author: Community, 2014-05-05

4 answers

Po pierwsze, dziedziczenie nie ma naturalnego tłumaczenia na architekturę relacyjnej bazy danych (ok, wiem, obiekty typu Oracle i niektóre inne RDBMS wspierają dziedziczenie, ale django nie korzysta z tej funkcjonalności)

W tym momencie zauważ, że django generuje nowe tabele do podklas i zapisuje wiele left joins Aby pobrać dane z tej 'tabel podrzędnych' . / Align = "left" / W scenariuszu wysokiej wydajności, podobnie jak backend gry lub coś innego, powinieneś go unikać i rozwiązywać dziedziczenie "ręcznie" za pomocą niektórych artefaktów, takich jak nulls, OneToOne lub klucze obce. W scenariuszu OneToOne można wywołać powiązaną tabelę bezpośrednio lub tylko wtedy, gdy jest ona potrzebna.

... Ale ...

"In my opinion (TGW)" powinieneś uwzględnić dziedziczenie modelowe w swoich projektach korporacyjnych, gdy trafi ono do twojego wszechświata dyskursu. Robię to i oszczędzam wiele godzin na rozwoju do mojego klienci dzięki tej funkcji. Również kod staje się czysty i elegancki A to oznacza łatwą konserwację (Uwaga niż tego rodzaju projekty nie mają setek lub żądań za sekundę)

Pytanie po pytaniu

P: Co jest nie tak z tego rodzaju dziedziczeniem w Django?
Odp: dużo tabel, dużo lewych łączników.

P: Dlaczego explicit OneToOneFields jest lepszy?
O: możesz uzyskać dostęp bezpośrednio do powiązanego modelu bez lewych złączeń.

P: czy są jakieś przykłady (benchmarki)?
O: nie porównywalne.

P: czy select_related() nie pozwala nam kontrolować, kiedy wywoływane są połączenia?
Odp: django dołącza do potrzebnych tabel.

P: Jakie są alternatywy dla dziedziczenia wielu tabel, gdy muszę odwołać się do klasy bazowej w innym modelu?
Odp: Unieważnienie. Relacje OneToOne i wiele linii kodu. To zależy od potrzeb aplikacji.

P: Czy GenericForeignKeys są lepsze w tym przypadku?
ODP: nie dla ja.

P: Co zrobić, jeśli potrzebuję OneToOneField do modelu bazowego? Odp: napisz. Nie ma z tym problemu. Na przykład, można rozszerzyć Model użytkownika, a także można mieć OneToOne do modelu bazowego użytkownika dla niektórych użytkowników.

Wniosek

Powinieneś znać koszt zapisu i utrzymania kodu bez dziedziczenia modelu, a także koszt sprzętu do obsługi aplikacji dziedziczenia modelu i odpowiedniego działania.

 19
Author: dani herrera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:10

Z tego, co rozumiem, używasz {[1] } na RelatedModel do BaseModel, ponieważ ostatecznie chcesz mieć łącze jeden do jednego między RelatedModel i każdym Submodel1 do Submodel9. Jeśli tak, istnieje bardziej efektywny sposób na zrobienie tego bez dziedziczenia wielostolikowego ani ogólnych relacji.

Wystarczy pozbyć się BaseModel i w każdym SubmodelX mieć OneToOneField do 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()

Umożliwiłoby to dostęp do SubmodelX z instancji RelatedModel za pomocą pola o nazwie the_thing, tak jak w dziedziczeniu wielostolikowym przykład, który dałeś jako pierwszy.

Zauważ, że możesz użyć dziedziczenia abstrakcyjnego do uwzględnienia pola related_model i innych wspólnych pól między SubModel1 a Submodel9.

Używanie dziedziczenia wielu tabel jest nieefektywne, ponieważ generuje dodatkową tabelę dla modelu bazowego, a tym samym dodatkowe łącza, aby uzyskać dostęp do tych pól. Używanie relacji generycznych byłoby bardziej efektywne, jeśli później okaże się, że zamiast tego potrzebujesz pola ForeignKey z RelatedModel do każdego SubmodelX. Jednak Django nie wspieraj ogólne relacje w select_related() i być może będziesz musiał zbudować własne zapytania, aby zrobić to efektywnie. Kompromis między wydajnością a łatwością kodowania zależy od Ciebie, w zależności od tego, ile obciążenia oczekujesz na serwerze i ile czasu chcesz poświęcić na optymalizację.

 10
Author: user193130,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-08 16:48:29

Świat się zmienił.

Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że artykuł zatytułowany Django gotcha: concrete inheritance miał prawie cztery lata w czasie, gdy zadano to pytanie; w 2014 roku. Zarówno systemy Django, jak i RDBMS przeszły długą drogę od tego czasu(przykład mysql 5.0 lub 5.1 były powszechnie używanymi wersjami, A 5.5 general availability był jeszcze miesiąc).

Dołącza do mojej lewej, dołącza do mojej prawej

Prawdą jest, że dziedziczenie wielu tabel powoduje extra dołącza za kulisami przez większość czasu . / Align = "left" / Warto zauważyć, że w odpowiednio znormalizowanej bazie danych prawie zawsze musisz dołączyć, aby pobrać wszystkie wymagane dane. W przypadku użycia odpowiednich indeksów, łączniki nie zawierają żadnych znaczących kar wydajnościowych.

INNER JOIN vs LEFT OUTER JOIN

Tak jest rzeczywiście w przypadku dziedziczenia wielu tabel, przy innych podejściach możliwe jest uniknięcie kosztownego lewego zewnętrznego łączenia i zrobienie wewnętrznego łączenia zamiast tego, a może subquery. Ale w przypadku dziedziczenia wielu tabel nie masz możliwości wyboru

 5
Author: e4c5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-19 01:20:42

Django implementuje dziedziczenie wielu tabel poprzez automatycznie utworzone OneToOneField jako swoje dokumenty says.So albo używaj abstrakcyjnego dziedziczenia, albo nie sądzę, aby użycie jawnego OneToOneFields lub ForeignKeys powodowało jakiekolwiek różnice.

 0
Author: youngjack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-02 01:22:00