Warum es langsam ist :Wenn Sie einfach die Anmerkung durch zwei ManyToMany-Felder verwendet haben dann erstellen Sie einen unerwünschten großen Join all dieser Tabellen zusammen. Die Größe des kartesischen Produkts von Zeilen, die ausgewertet werden müssen, beträgt ungefähr Have.objects.count() * Want.objects.count()
. Du hast dann distinct=True
geschrieben um endlich die Anzahl der duplizierten Elemente einzuschränken, um kein ungültiges riesiges Ergebnis zu erhalten.
Fix für altes Django:Wenn Sie nur queryset.annotate(have_count=Count("have"))
verwenden würden Ohne distinct=True
erhalten Sie schnell das richtige Ergebnis oder das gleiche Ergebnis auch schnell mit deutlich. Dann können Sie die Ergebnisse zweier Abfragen von Python im Speicher kombinieren.
Lösung Eine nette Lösung ist in Django>=1.11 möglich (zwei Jahre nach Ihrer Frage) indem Sie eine Abfrage mit verwenden zwei Unterabfragen , eine für Have
und eine für Want
, alle auf eine Anfrage, aber nicht alle Tische zusammen zu mischen.
from django.db.models import Count, OuterRef, Subquery
sq = Collection.objects.filter(pk=OuterRef('pk')).order_by()
have_count_subq = sq.values('have').annotate(have_count=Count('have')).values('have_count')
want_count_subq = sq.values('want').annotate(have_count=Count('want')).values('want_count')
queryset = queryset.annotate(have_count=Subquery(have_count_subq),
want_count=Subquery(want_count_subq))
Bestätigen :Sie können sowohl die langsame als auch die feste SQL-Abfrage überprüfen, indem Sie str(my_queryset.query)
ausgeben dass es so ist wie oben beschrieben.