Opened 8 years ago

Closed 8 years ago

#4739 closed (wontfix)

len(queryset) is slow

Reported by: tclugg@… Owned by: adrian
Component: Database layer (models, ORM) Version: master
Severity: Keywords: queryset, len, count, select
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

len(queryset) uses queryset.iterator, which performs SQL SELECT instead of SQL COUNT. queryset.len should instead call queryset.count() which is much faster as it will use the cached result of SELECT if available, otherwise performing a SQL COUNT.

Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py (revision 5583)
+++ django/db/models/query.py (working copy)
@@ -106,7 +106,7 @@

return repr(self._get_data())

def len(self):

  • return len(self._get_data())

+ return self.count()

def iter(self):

return iter(self._get_data())

Change History (2)

comment:1 Changed 8 years ago by tclugg@…

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

The patch again wrapped in a code block:

Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py   (revision 5583)
+++ django/db/models/query.py   (working copy)
@@ -106,7 +106,7 @@
         return repr(self._get_data())

     def __len__(self):
-        return len(self._get_data())
+        return self.count()

     def __iter__(self):
         return iter(self._get_data())

comment:2 Changed 8 years ago by mtredinnick

  • Resolution set to wontfix
  • Status changed from new to closed

Your solution requires a second database query, which isn't so great.

If a user only wants the size of a set of results, they can call count() explicitly. If they are calling len() on the queryset, then they've already created the queryset for other reasons, so actually using the results we've already queried is efficient (recalling that the queryset is going to cache the results anyway).

All that being said, one enhancement that will be introduced soon is to speed up len() for most database backends by using the cursor's rowcount attribute and (only if that isn't implemented) then falling back to the size of the result set.

So, yes, we can make len() slightly more efficient for most database backends (not SQLite, but life's like that sometimes), but it isn't going to be by making another database call.

Note: See TracTickets for help on using tickets.
Back to Top