我的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 | |
+----+-------------+--------------------+------+-----------------------------+-----------------------------+---------+-------------------------------+------+---------------------------------+
答案 0 :(得分:1)
这已经是最好的方法了。如果它很慢,问题可能在于您的数据库 - 具体而言,您没有该查询的正确索引,因此数据库必须进行太多的排序。
Django调试工具栏非常适合诊断此类事情 - 它将显示每个查询所花费的时间,并允许您在每个查询上运行db的EXPLAIN函数。 MySQL文档将告诉您EXPLAIN的输出意味着什么。但是,之后由您来优化数据库。
答案 1 :(得分:1)
当你尝试使用未定义索引的order_by子句时,尝试在其上定义索引,它使得排序过程更快,在你的情况下'num_favorites'上的索引是加速查询执行所需的时间。你使用的技术也很好,没有什么不好的。
请参阅我在同一问题上提出的related question,saverio
给出了解决问题的绝佳答案。希望这会有所帮助。