Por que é lento :Se você simplesmente usou a anotação por dois campos ManyToMany então você cria uma grande junção indesejada de todas essas tabelas juntos. O tamanho do produto cartesiano de linhas que devem ser avaliadas é aproximadamente
Have.objects.count() * Want.objects.count()
. Você escreveu então distinct=True
para restringir finalmente o número de itens duplicados para não obter um resultado enorme inválido. Correção para o antigo Django:Se você usar apenas
queryset.annotate(have_count=Count("have"))
você obterá o resultado certo rapidamente sem distinct=True
ou o mesmo resultado também rápido com distintos. Então você pode combinar os resultados de duas consultas por Python na memória. Solução Uma boa solução é possível no Django>=1.11 (dois anos após sua pergunta) usando uma consulta com duas subconsultas , um para
Have
e um para Want
, tudo por uma solicitação, mas não para misturar todas as tabelas. 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))
Verificar :Você pode verificar a consulta SQL lenta e fixa imprimindo
str(my_queryset.query)
que seja como descrito acima.