Python Django查询集上的Count vs len
在Django中,假设我有一个Python Django查询集上的Count vs len,python,django,performance,Python,Django,Performance,在Django中,假设我有一个QuerySet,我将迭代并打印结果,那么计算对象的最佳选项是什么len(qs)或qs.count() (同时考虑到在同一迭代中计算对象不是一个选项。)尽管建议使用count而不是len: 注意:如果您只想确定集合中的记录数,请不要在查询集上使用len()。使用SQL的SELECT count(*),在数据库级别处理计数要高效得多,Django正是出于这个原因提供了count()方法 由于您无论如何都在迭代此查询集(除非您正在使用),因此最好使用len,因为这样可以
QuerySet
,我将迭代并打印结果,那么计算对象的最佳选项是什么len(qs)
或qs.count()
(同时考虑到在同一迭代中计算对象不是一个选项。)尽管建议使用count
而不是len
:
注意:如果您只想确定集合中的记录数,请不要在查询集上使用len()。使用SQL的SELECT count(*)
,在数据库级别处理计数要高效得多,Django正是出于这个原因提供了count()
方法
由于您无论如何都在迭代此查询集(除非您正在使用),因此最好使用len
,因为这样可以避免再次访问数据库,也可以避免检索不同数量的结果
如果您使用的是迭代器
,那么出于同样的原因,我建议在迭代过程中包含一个计数变量(而不是使用count)。我认为在这里使用len(qs)
更有意义,因为您需要迭代结果qs.count()
是一个更好的选择,如果您只想打印计数,而不是迭代结果
len(qs)
将使用select*from table
命中数据库,而qs.count()
将使用select count(*)from table
命中数据库
另外,qs.count()
将给出返回整数,您无法对其进行迭代在len()
和count()
之间进行选择取决于具体情况,值得深入了解它们如何正确使用
让我为您提供几个场景:
(最重要的)当您只想知道元素的数量,而不打算以任何方式处理它们时,使用count()
:
DO:queryset.count()
-这将执行单个选择count(*)某些表的查询,所有计算都在RDBMS端进行,Python只需检索结果编号,固定成本为O(1)
不要:len(queryset)
-这将执行SELECT*从一些表中
查询,获取整个表O(N)并需要额外的O(N)内存来存储它这是可以做的最糟糕的事情
当您打算无论如何获取queryset时,最好使用len()
,这不会像count()
那样导致额外的数据库查询
len()
(一个数据库查询)
count()
(两个数据库查询!):
还原的第二种情况(当已获取queryset时):
只要看一眼“引擎盖下”,一切都会变得清晰:
Django文档中的良好参考:
对于喜欢测试测量的人(Postresql):
如果我们有一个简单的人物模型和1000个实例:
class Person(models.Model):
name = models.CharField(max_length=100)
age = models.SmallIntegerField()
def __str__(self):
return self.name
在一般情况下,它给出:
In [1]: persons = Person.objects.all()
In [2]: %timeit len(persons)
325 ns ± 3.09 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: %timeit persons.count()
170 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
那么,在这个特定的测试用例中,您如何看到count()
比len()
快几乎2x。总结其他人已经回答的问题:
len()
将获取所有记录并对其进行迭代
count()
将执行SQL计数操作(处理大型查询集时速度要快得多)
同样正确的是,如果在这个操作之后,整个查询集将被迭代,那么作为一个整体,使用len()
可能会稍微有效一些
但是
在某些情况下,例如当内存有限时,可以方便地(在可能的情况下)分割在记录上执行的操作。
这可以通过使用
然后,可以选择使用count()
,这样可以避免一次获取整个查询集。有趣的问题。我建议对此进行分析。。我会很感兴趣的!我对python的了解还不够,不知道完全求值对象上的len()是否有很多开销。它可能比数数还快!回答得很好,+1用于在上下文中发布QuerySet
实现。这确实是一个完美的答案。解释使用什么,更重要的是,解释使用的原因。
for obj in queryset: # iteration fetches the data
len(queryset) # using already cached data - O(1) no extra cost
queryset.count() # using cache - O(1) no extra db query
len(queryset) # the same O(1)
queryset.count() # the same: no query, O(1)
class QuerySet(object):
def __init__(self, model=None, query=None, using=None, hints=None):
# (...)
self._result_cache = None
def __len__(self):
self._fetch_all()
return len(self._result_cache)
def _fetch_all(self):
if self._result_cache is None:
self._result_cache = list(self.iterator())
if self._prefetch_related_lookups and not self._prefetch_done:
self._prefetch_related_objects()
def count(self):
if self._result_cache is not None:
return len(self._result_cache)
return self.query.get_count(using=self.db)
class Person(models.Model):
name = models.CharField(max_length=100)
age = models.SmallIntegerField()
def __str__(self):
return self.name
In [1]: persons = Person.objects.all()
In [2]: %timeit len(persons)
325 ns ± 3.09 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: %timeit persons.count()
170 ns ± 0.572 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)