2016-09-26 84 views
0

我的问题的更一般的版本已经比克问:Count vs len on a Django QuerySet计数VS LEN在Django的查询集时的一些结果进行过滤

我的情况有点不同,虽然。它开始是这样的:

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使第二个更有效率?

我会接受'简介'作为答案,但我想知道这些解决方案是否被认为是最佳实践。

+0

你以后使用了那些请求的消息,还是只想得到两个数字,就是这样?预计在原始过滤列表中有多少条消息(几十,几千条)?列表中错误的预期比例是多少? – serg

+0

好问题,但我其实不确定答案。这些数字用于页面顶部的状态图标;用户可以点击它来查看消息,或忽略它。我不确定消息的数量,但是如果有超过数十个消息,我会感到惊讶(在我的情况下,这个问题更多是关于风格而不是性能,但有人可能会有相同的问题,申请一天)。我也不确定会出现错误的比例;用户希望它非常小,但实际上取决于第三方数据的质量。 –

回答

2

据我所知,如果你检索所有的对象并逐个检查一个布尔值,这不是好的方法,因为你使用使用内存的python来完成它。 另一方面,'count'在数据库中执行,您不必为了检查一个布尔值而获取所有行。因此,我认为好的方式是中间的方式。此外,当你定义'消息'时,它是一个查询集,但它不会在db中执行,直到你需要它使用懒惰评估。所以,如果你为该查询集使用for循环,它将直接执行它。但是,如果您为所需的布尔值添加其他过滤器,则它只会更新数据库查询。这就是为什么它的性能更好。

+0

我很确定这三种方法中的任何一种都会导致两个查询。我期望在创建'messages'对象时执行查询,并为该对象的生命期缓存结果。 (如果生成器函数为每次迭代重新执行查询,我会对Django感到惊讶和深深失望!)但是我认为你是对的,期望DB服务器被调优以比代码更有效地过滤错误是公平的客户端。谢谢。 –

+1

它不会为每个迭代执行查询。但主要的是,如果你可以在数据库中做到这一点,那就做吧。如果没有办法,那就考虑提取所有信息并重复它。因此,计数函数使用数据库中的计数并且执行得非常快。祝你有美好的一天:) –

1

要在它们之间做出决定:

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确实会给你一个清晰的画面。如果你的表格尺寸很小(例如数千条,那没关系)。如果它是数百万条目的顺序,则应该很容易通过配置文件获得清晰的图像。

+0

嗯,是的,我应该索引is_error列。感谢您的提醒。 ☺ –