【问题标题】:Count vs len on a Django QuerySet when some results are filtered过滤某些结果时,在 Django QuerySet 上计数 vs len
【发布时间】:2016-09-26 20:55:30
【问题描述】:

已经提出了我的问题的更一般版本:Count vs len on a Django QuerySet

不过,我的情况有点不同。开头是这样的:

messages = Message.objects.filter(foo=bar)

获取error_message_countother_message_count,哪个更好?

error_message_count = len(message for message in messages if message.is_error)
other_message_count = len(messages) - error_message_count

或:

error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count

甚至:

error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.filter(is_error = False).count()

我怀疑第一个解决方案归结为只有一个查询,而其他解决方案则归结为两个。但也许 Django 和/或 DBMS 使后两个中的一个更有效率?

我会接受“profile it”作为答案,但我想知道这些解决方案是否被认为是最佳实践。

【问题讨论】:

  • 您是在之后使用那些请求的消息,还是只想获得两个数字,仅此而已?原始过滤列表中预计有多少消息(数十、数千)?列表中的预期错误率是多少?
  • 好问题,但我实际上不确定答案。这些数字用于页面顶部的状态图标;用户可以点击它来查看消息,或者忽略它。我不确定消息的数量,但如果有几十条消息,我会感到惊讶(所以在我的情况下,这个问题更多的是关于风格而不是性能,但有人可能对一个非常不同的问题有同样的问题某天申请)。我也不确定错误的比例;用户希望它非常小,但这实际上取决于第三方数据的质量。

标签: django django-models


【解决方案1】:

据我所知,如果您检索所有对象并逐个检查布尔值,这不是一个好方法,因为您使用的是使用内存的 python 来做到这一点。 另一方面,'count' 在数据库中执行,您不必为了检查一个布尔值而获取所有行。因此,我认为好的方法是中间的。

error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count

此外,当您定义“消息”时,它是一个查询集,但在您需要它使用惰性评估之前,它不会在数据库中执行。因此,如果您对该查询集使用 for 循环,它将直接执行它。但是,如果您为所需的布尔值添加另一个过滤器,它只会更新数据库查询。这就是为什么它的性能更好。

【讨论】:

  • 我很确定这三种方法中的任何一种都会导致两个查询。我希望在创建 messages 对象时执行查询,并在该对象的生命周期内缓存结果。 (如果生成器函数为每次迭代重新执行查询,我会对 Django 感到惊讶和深感失望!)但我认为你是对的,期望 DB 服务器被调整以比代码更有效地过滤错误是公平的客户端。谢谢。
  • 它不会为每次迭代执行查询。但主要的是,如果您可以在数据库中执行此操作,请在此处执行。如果没有办法,那就考虑拉取所有的信息并迭代它。因此,执行 count 函数在数据库中使用 count 并且执行得非常快。祝你有美好的一天:)
【解决方案2】:

在这些之间做出决定:

error_message_count = len(message for message in messages if message.is_error)
other_message_count = len(messages) - error_message_count

或:

error_message_count = messages.filter(is_error = True).count()
other_message_count = messages.count() - error_message_count

有一些重要的因素需要考虑,例如您在is_error 上是否有索引、messages 表的大小是多少以及您期望有多少+ve / -ve 匹配。不幸的是,profile-it 确实会给你一个清晰的画面。如果您的表格很小(例如几千个条目,没关系)。如果它是数百万个条目的数量级,那么通过个人资料获得清晰的图片应该相当容易。

【讨论】:

  • 嗯,是的,我应该索引 is_error 列。感谢您的提醒。 ☺
猜你喜欢
  • 2012-12-28
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 1970-01-01
  • 2018-01-21
  • 2018-01-05
  • 2013-09-08
相关资源
最近更新 更多