【发布时间】:2015-05-25 13:27:13
【问题描述】:
总结:在计算相关对象时,我使用很少的查询和注释与每个项目额外的两个查询相比,查询速度非常慢。数据库是 PostgreSQL 9.3.5。
我有一个看起来像这样的模型:
class Collection(models.Model):
have = models.ManyToManyField(Item, related_name='item_have', through='Have')
want = models.ManyToManyField(Item, related_name='item_want', through='Want')
added = models.DateTimeField()
class Meta:
ordering = ['-last_bump']
class Have(models.Model):
item = models.ForeignKey(Item)
collection = models.ForeignKey(Collection, related_name='have_set')
price = models.IntegerField(default=0)
class Want(models.Model):
want = models.ForeignKey(Item)
collection = models.ForeignKey(Collection, related_name='want_set')
price = models.IntegerField(default=0)
在我看来,我列出了这些集合,我想通过注释来显示每个集合中有多少想要和拥有的数量:
class ListView(generic.ListView):
model = Collection
queryset = Collection.objects.select_related()
paginate_by = 20
def get_queryset(self):
queryset = super(ListView, self).get_queryset()
queryset = queryset.annotate(have_count=Count("have", distinct=True),
want_count=Count("want", distinct=True))
但是,这使我的查询非常慢!我在数据库中有大约 650 条记录,django-debug-toolbar 说它进行 2 次查询,平均大约 400-500 毫秒。我已经尝试过使用 prefetch_related,但它并没有让它变得更快。
我确实尝试了另一件事,在 Collection 模型中,我添加了这个:
@property
def have_count(self):
return self.have.count()
@property
def want_count(self):
return self.want.count()
并从我的视图中删除了注释。相反,它总共对数据库进行 42 次查询,但在 20-25 毫秒内完成。
我在这里的注释做错了什么?在一个查询中进行计数是否应该比进行多次计数查询更快?
【问题讨论】:
-
一个建议,在询问有关调试慢查询的问题时,使用调试工具栏获取正在运行的 sql 查询并为它们运行 EXPLAIN 查询。并在您的问题中发布这些 sql 查询和 EXPLAIN,这样其他人会更容易回答。
-
"在一个查询中进行计数是否比进行多次计数查询更快?"为什么会这样? SQL 是一种有趣的动物。我怀疑您正在生成巨大的笛卡尔积,然后将它们压缩到内存中的计数中,而与
count()一样,您只是在运行超快速的一次select count(*) from table;查询。 -
我认为这是 django annotate + postgres 的组合。我现在遇到了同样的问题,我正在将所有注释“迁移”到 .count()。它工作得更快
-
如果您真的在问“是什么阻碍了查询?”我认为独特的东西正在减慢它的速度。如果没有它,你就不会得到你想要的东西。您可以尝试使其与存储过程一起使用。
标签: python django postgresql