在Django QuerySet上计算vs len

问题描述 投票:65回答:3

在Django中,鉴于我有一个QuerySet,我将迭代并打印结果,计算对象的最佳选择是什么? len(qs)qs.count()

(另外,在同一次迭代中计算对象不是一种选择。)

python django performance
3个回答
96
投票

虽然Django docs建议使用count而不是len

注意:如果您只想确定集合中的记录数,请不要在QuerySets上使用len()。使用SQL的SELECT COUNT(*)处理数据库级别的计数效率要高得多,而Django正是因为这个原因提供了count()方法。

既然你正在迭代这个QuerySet,the result will be cached(除非你使用的是iterator),所以最好使用len,因为这样可以避免再次访问数据库,也可能检索不同数量的结果!)。 如果您正在使用iterator,那么我会建议在迭代时使用计数变量(而不是使用计数),原因相同。


28
投票

选择len()count()取决于具体情况,值得深入了解他们如何正确使用它们。

让我为您提供一些场景:

  1. (最关键)当你只想知道元素的数量并且你不打算以任何方式处理它们时,使用count()至关重要: DO:queryset.count() - 这将执行单个SELECT COUNT(*) some_table查询,所有计算都在RDBMS端进行,Python只需要以固定成本O(1)检索结果数 请勿:len(queryset) - 这将执行SELECT * FROM some_table查询,获取整个表O(N)并需要额外的O(N)内存来存储它。这是最糟糕的事情
  2. 当你打算获取查询集时,使用len()稍微好一些,这不会导致额外的数据库查询,因为count()会: len(queryset) # fetching all the data - NO extra cost - data would be fetched anyway in the for loop for obj in queryset: # data is already fetched by len() - using cache pass 计数: queryset.count() # this will perform an extra db query - len() did not for obj in queryset: # fetching data pass
  3. 还原的第二种情况(已经提取了查询集): 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)

Django文档中的好参考:


23
投票

我认为使用len(qs)在这里更有意义,因为你需要迭代结果。 qs.count()是一个更好的选择,如果你想要做的就是打印计数而不是迭代结果。

qazxsw poi将用qazxsw poi击中数据库,而qazxsw poi将用len(qs)击中数据库。

select * from table也会给出返回整数,你不能迭代它

© www.soinside.com 2019 - 2024. All rights reserved.