PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Pourquoi ce décompte d'annotations Django (1.6) est-il si lent ?

Pourquoi c'est lent :Si vous avez simplement utilisé l'annotation par deux champs ManyToMany puis vous créez une grande jointure indésirable de toutes ces tables ensemble. La taille du produit cartésien des lignes à évaluer est d'environ Have.objects.count() * Want.objects.count() . Vous avez alors écrit distinct=True pour limiter enfin le nombre d'éléments dupliqués pour ne pas obtenir un énorme résultat invalide.

Correctif pour l'ancien Django :si vous n'utilisiez que queryset.annotate(have_count=Count("have")) vous obtiendrez le bon résultat rapidement sans distinct=True ou le même résultat aussi rapide avec distinct. Ensuite, vous pouvez combiner les résultats de deux requêtes par Python en mémoire.

Solution Une belle solution est possible dans Django>=1.11 (deux ans après votre question) en utilisant une requête avec deux sous-requêtes , un pour Have et un pour Want , le tout en une seule demande, mais pas pour mélanger toutes les tables ensemble.

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))

Vérifier  :Vous pouvez vérifier à la fois la requête SQL lente et la requête SQL fixe en imprimant str(my_queryset.query) que c'est comme décrit ci-dessus.