3

我正在评估一个 QuerySet,然后是另一个,但第二个是第一个的子集。我试图以一种有效的方式做到这一点,尽可能少地调用数据库。(以前有人问过这个问题,但老实说,我并没有完全理解答案,我不确定它们是否完全适用于我的想法。)

使用 Django 文档的示例 Weblog 模型,在视图中,这是尝试优化之前的代码:

myblog = Blog.objects.get(pk=1)

d={} #going to pass this to my template

# not using count()
d['num_of_entries'] = len(myblog.entry_set.all()) 

# not using exists()
d['is_jolly'] = bool(Entry.objects.filter(blog=myblog, headline__startswith='Jolly'))

# ... other code but no further use of database in this view

第二个 QuerySet 是第一个的子集。我是否应该尝试使用纯 Python 来获取子集(因此只评估一个 QuerySet - 少一个数据库调用)?

或者,也许只需执行以下操作?

# other code as above

d['num_of_entries'] = myblog.entry_set.count()

d['is_jolly'] = Entry.objects.filter(blog=myblog, headline__startswith='Jolly').exists()

# ... other code but no further use of database in this view
4

1 回答 1

6

“尽可能少的数据库查询”不是正确的标准。您还想考虑这些数据库查询完成的工作量,以及从数据库传输到 Django 服务器的数据量。

让我们考虑两种实现您所追求的方法。方法一:

entries = myblog.entry_set.all()
num_of_entries = len(entries)
is_jolly = any(e.headline.startswith('Jolly') for e in entries)

方法二:

num_of_entries = myblog.entry_set.count()
is_jolly = Entry.objects.filter(blog=myblog, headline__startswith='Jolly').exists()

在方法 1 中,有一个数据库查询,但该查询将类似于SELECT * FROM ENTRY WHERE .... 它可能会获取大量条目,并将它们的所有内容通过网络传输到您的 Django 服务器,然后将几乎所有这些内容扔掉(它实际查看的唯一字段是headline字段)。

在方法 2 中,有两个数据库查询,但第一个是SELECT COUNT(*) FROM ENTRY WHERE ...仅获取一个整数的 a,第二个是SELECT EXISTS(...)仅获取一个布尔值的 a。由于这些查询不必获取所有匹配的条目,因此数据库有更多的可能性来优化查询。

因此,在这种情况下,方法 2 看起来要好得多,即使它发出更多查询。

于 2013-01-14T18:05:14.357 回答