3

annotate() 让事情变得缓慢是正常的吗?

像这样使用注释:

post_list = j.post_set.all().annotate(num_comments=Count('comment')).order_by('-pub_date')

使它花费了不做注释的四倍:

post_list = j.post_set.all().order_by('-pub_date')

我还尝试了 values() 和 defer() ,但这些也没有帮助。将评论数量保留为 Post 表中的一个字段是唯一真正的选择吗?

顺便说一句,我正在使用 MySQL。

4

4 回答 4

3

了解查询为何运行缓慢的一种方法是实际查看生成的 SQL。

最简单的方法是在 django shell 中执行此操作:

>>> j.post_set.all().annotate(num_comments=Count('comment')).order_by('-pub_date')
>>> print j.query

您可能会发现重新排序链式查询集方法可能会改变性能:

>>> j.post_set.order_by('-pub_date').annotate(num_comments=Count('comment'))
于 2013-07-08T03:26:51.077 回答
3

我知道这已经晚了,但请尝试:

j.post_set.all().extra({'num_comments': 'SELECT COUNT(*) FROM Comment WHERE Comment.post_id = post.id'}).order_by('pub_date')

(更改表名)

至少在 postgres 9.2+ 上,它产生的查询比使用注释快得多。

Annotate 尝试使用左外连接,然后按分组生成最终结果,而上面的额外子句将子查询添加到选定的列中。后者可以让数据库更好地利用现有的数据库索引。

于 2014-03-08T10:50:20.557 回答
1

post_list = j.post_set.all().order_by('-pub_date')因此,对于您正在对单个表的数据库进行查询的简单情况。这会很快,如果你在pub_date字段上添加索引会更快。并ordering = ['-pub_date']在 Post 的 Meta 部分中设置。

对于作为注释的更复杂的情况,对于您要求的每条记录,它都需要在相关表中进行查找并计算返回的条目数。这必然比简单的情况花费更长的时间,即使它直接从索引中提取数据。

对于故障排除,我建议您安装django-debug-toolbar,查看它的查询选项卡,找到使您变慢的查询,然后运行该explain工具以获取有关使您变慢的额外信息。该工具将向您显示生成的确切 SQL,以及查询的哪些部分“花费”最多。

如果它让你慢下来,也许你应该考虑将这些信息存储在缓存中。或者使用像 postgres 这样的数据库,它允许您将这种元信息存储在自定义索引中。

于 2013-07-08T01:36:57.077 回答
1

我知道这有点晚了,但我最终在这里尝试用 Count() 解决类似的问题。我使用了 Matthew Schinckel 的想法,即使用 shell 来找出正在执行的 SQL。然后,我打开 pgAdmin,粘贴查询并执行。令我惊讶的是,执行查询是我的 Django 应用程序所花费时间的最大部分。

我的应用程序使用几何字段,并且由于未在我的查询集中列出所需的字段,因此 Group By 子句包括所有表字段 - 包括一个非常大的 geom 字段。

在查看了QuerysetAPI Reference 之后,我在我的查询集中包含了 .Values() 以及一个简短的字段列表。这将我的查询时间从 5 秒减少到 10 毫秒左右!

于 2015-11-24T19:53:22.897 回答