Django QuerySet 上的 Count() 与 len()

新手上路,请多包涵

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

(还考虑到在同一次迭代中计算对象的数量不是一种选择。)

原文由 antonagestam 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

len()count() 之间进行选择取决于具体情况,值得深入了解它们的工作原理以正确使用它们。

让我为您提供几个场景:

  1. (最关键)当您只想知道元素的数量而不打算以任何方式处理它们时,使用 count() 至关重要:

DO: queryset.count() - 这将执行单个 SELECT COUNT(*) FROM some_table 查询,所有计算都在 RDBMS 端进行,Python 只需要以 O(1) 的固定成本检索结果编号

不要: len(queryset) - 这将执行 SELECT * FROM some_table 查询,获取整个表 O(N) 并需要额外的 O(N) 内存来存储它。 这是最糟糕的情况

  1. 当您打算无论如何获取查询集时,使用 len() 会稍微好一点,这不会导致额外的数据库查询,因为 count()

len() (一个数据库查询)

     len(queryset) # SELECT * 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

count() (两个数据库查询!):

     queryset.count() # First db query SELECT COUNT(*)

    for obj in queryset: # Second db query (fetching data) SELECT *
        pass

  1. 恢复第二种情况(当查询集已经被获取时):
     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 文档中的良好参考资料:

原文由 Krzysiek 发布,翻译遵循 CC BY-SA 4.0 许可协议

尽管 Django 文档 建议使用 count 而不是 len

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

由于您无论如何都在迭代此 QuerySet, 结果将被缓存(除非您正在使用 iterator ),因此最好使用 len ,因为 这样可以避免再次访问数据库,还有可能检索到不同数量的结果!)。

如果您使用的是 iterator ,出于同样的原因,我建议您在迭代(而不是使用计数)时包括一个计数变量。

原文由 Andy Hayden 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题