Django:根据相关字段的数量订购QuerySet的最快方法是什么?

时间:2011-08-17 06:52:09

标签: mysql django django-queryset

我的Django应用程序中有一个Item模型,其中有一个ManyToMany字段,该字段是通过中间收藏夹模型处理的。以下是相关模型的简化版本:

class Item(models.Model):
    name = models.CharField(max_length=200)

class Favorite(models.Model):
    user = models.ForeignKey(User)
    item = models.ForeignKey(Item)

我正在尝试获取按收藏夹数量排序的项目列表。下面的查询有效,但Item表中有数千条记录,查询最多需要几分钟才能完成。

items = Item.objects.annotate(num_favorites=Count('favorite')).order_by('-num_favorites')

不确定这是否与任何可能的答案相关,但我使用Django的内置Pagintor对结果进行分页:

paginator = Paginator(items, 100)

我知道我可以在我的项目模型中添加favorites字段,并在每次项目被收藏时增加该字段,但我想知道是否有另一种更清晰,更有效的方法在合理的时间内检索此数据。

以下是MySQL EXPLAIN函数的输出:

+----+-------------+--------------------+------+-----------------------------+-----------------------------+---------+-------------------------------+------+---------------------------------+
| id | select_type | table              | type | possible_keys               | key                         | key_len | ref                           | rows | Extra                           |
+----+-------------+--------------------+------+-----------------------------+-----------------------------+---------+-------------------------------+------+---------------------------------+
|  1 | SIMPLE      | appname_item       | ALL  | NULL                        | NULL                        | NULL    | NULL                          |  566 | Using temporary; Using filesort |
|  1 | SIMPLE      | appname_favorite   | ref  | appname_favorite_67b70d25   | appname_favorite_67b70d25   | 4       | appname.appname_item.id       |    1 |                                 |
+----+-------------+--------------------+------+-----------------------------+-----------------------------+---------+-------------------------------+------+---------------------------------+

2 个答案:

答案 0 :(得分:1)

这已经是最好的方法了。如果它很慢,问题可能在于您的数据库 - 具体而言,您没有该查询的正确索引,因此数据库必须进行太多的排序。

Django调试工具栏非常适合诊断此类事情 - 它将显示每个查询所花费的时间,并允许您在每个查询上运行db的EXPLAIN函数。 MySQL文档将告诉您EXPLAIN的输出意味着什么。但是,之后由您来优化数据库。

答案 1 :(得分:1)

当你尝试使用未定义索引的order_by子句时,尝试在其上定义索引,它使得排序过程更快,在你的情况下'num_favorites'上的索引是加速查询执行所需的时间。你使用的技术也很好,没有什么不好的。

请参阅我在同一问题上提出的related questionsaverio给出了解决问题的绝佳答案。希望这会有所帮助。