Search code examples
djangodjango-modelsormquery-optimizationdjango-queryset

Django ORM DB Query Optimization


I have a Query that consists of two DB hits.
which the first contains 'aggregate' - so it perform immediately.
I want to know if I can reduce it to only one DB hit.

The query is:
"Find customers that their id's numbers are bigger than all of texas's customers id's."

The two querysets are:

highest_tx_id = Customer.objects.filter(state='TX').aggregate(Max('id'))
res = Customer.objects.filter(id__gt=highest_tx_id['id_max'])

Adding an example:

>>> reset_queries()
>>> highest_tx_id = Customer.objects.filter(state='TX').aggregate(Max('id'))
>>> res = Customer.objects.filter(id__gt=highest_tx_id['id__max'])
>>> connection.queries
[{'sql': 'SELECT MAX("customer"."id") AS "id__max" FROM "customer" WHERE "customer"."state" = \'TX\'', 'time': '0.001'}]
>>> res
<QuerySet [<Customer: Customer object (550)>, <Customer: Customer object (551)>, <Customer: Customer object (552)>, <Customer: Customer object (553)>, <Customer: Customer object (555)>, <Customer: Customer object (661)>, <Customer: Customer object (665)>]>
>>> connection.queries
[{'sql': 'SELECT MAX("customer"."id") AS "id__max" FROM "customer" WHERE "customer"."state" = \'TX\'', 'time': '0.001'}, {'sql': 'SELECT "customer"."id", "customer"."fname", "customer"."lname", "customer"."address", "customer"."city", "customer"."state", "customer"."zip_code", "customer"."phone", "customer"."company_name" FROM "customer" WHERE "customer"."id" > 444 LIMIT 21', 'time': '0.001'}]      
>>>

Any way to do these type of queries using 1 DB hit ?


Solution

  • Building up on @TaipanRex's answer, you can do something like this:

    from django.db.models import Subquery
    
    highest_tx_id = Customer.objects.filter(state='TX').order_by('-id').values('id')[:1]
    res = Customer.objects.filter(id__gt=Subquery(highest_tx_id))