#28477: Strip unused annotations from count queries
-------------------------------------+-------------------------------------
Reporter: Tom Forbes | Owner: Tom
Type: | Forbes
Cleanup/optimization | Status: assigned
Component: Database layer | Version: master
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Reupen Shah):
I have also run into problems with `QuerySet.count()` being very slow on
annotated query sets. Django uses a subquery for the count but injects a
group by into the subquery. This typically causes the database server to
deduplicate all matched rows using the group by columns which is, in
general, extremely slow when there are a large number of matched rows.
For example, consider the following model:
{{{
class Person(models.Model):
"""Person model."""
first_name = models.TextField()
last_name = models.TextField()
country = models.TextField(null=True, blank=True)
}}}
and query set:
{{{
from django.db.models.functions import Concat
from django.db.models import Value
queryset = Person.objects.annotate(full_name=Concat('first_name', Value('
'), 'last_name'))
}}}
`queryset.count()` generates the following query under PostgreSQL:
{{{
SELECT COUNT(*)
FROM
(SELECT "support_person"."id" AS Col1,
CONCAT("support_person"."first_name", CONCAT(' ',
"support_person"."last_name")) AS "full_name"
FROM "support_person"
GROUP BY "support_person"."id",
CONCAT("support_person"."first_name", CONCAT(' ',
"support_person"."last_name"))) subquery
}}}
`list(queryset)` generates:
{{{
SELECT "support_person"."id",
"support_person"."first_name",
"support_person"."last_name",
"support_person"."country",
CONCAT("support_person"."first_name", CONCAT(' ',
"support_person"."last_name")) AS "full_name"
FROM "support_person"
}}}
I am not entirely sure why the subquery for the count needs to be any
different from the query used when the query set itself is evaluated.
There are some relevant comments in the source code here:
https://github.com/django/django/blob/5deb7a86e8b54d052a3b1dbed1ae7142d362b1c5/django/db/models/sql/query.py#L404-L414
This has all been tested under Django 2.1.7.
--
Ticket URL: <https://code.djangoproject.com/ticket/28477#comment:7>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/061.ac61c734d7172f23b1353d1018acb01a%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.