Django聚合产生了过多的GROUP BY子句

4

我正在使用Django ORM在MySQL上进行非常简单的聚合,它生成了一个包含非常大的data字段的GROUP BY子句,导致查询速度减慢了100倍以上。

下面是一个简化版的模型:

class Document(models.Model):
    data = models.TextField()

class Attachment(models.Model):
    document = models.ForeignKey(Document)

我正在运行的查询语句:

Document.objects.annotate(num_attachments=Count('attachment'))

并且SQL输出结果为:

SELECT
  `document_document`.`id`,
  `document_document`.`data`,
  COUNT(`document_attachment`.`id`) AS `num_attachments`
FROM `document_document`
  LEFT OUTER JOIN `document_attachment`
    ON (`document_document`.`id` = `document_attachment`.`document_id`) 
GROUP BY
  `document_document`.`id`,
  `document_document`.`id`,
  `document_document`.`data`
ORDER BY NULL

在数据字段上进行GROUP BY是不必要和荒谬的。我可以通过执行values查询来停止此操作:

Document.objects.values('pk').annotate(num_attachments=Count('attachment'))

但是,我要如何获得一个真正的带注释的文档查询结果?

很奇怪,我尝试了一个类似的外键示例,但它不起作用。我只能通过ManyToMany关系使其工作。我知道这是模型的简化版本,你可能有一个指向Document的不同ManyToManyField吗?或者有一个Document自引用字段,一个Document引用另一个Document吗? - Furbeenator
我设置了相同的模型并尝试了一下,只是我添加了一个 name = models.CharField(max_length=24),得到了类似的结果,只不过它对所有三个字段进行了两次 GROUP BY!肯定是一个 bug。我正在使用版本 1.3.1,结果也是一样的。 - Furbeenator
@Furbeenator 我在 Django 的错误跟踪器上没有找到任何相关信息。顺便说一下,我使用的是 1.3.0 版本。 - Christian Oudard
非常好,我看到你打开了一个错误票据并准备修补程序。看起来他们正在循环字段为每个循环中的字段创建GROUP BY,可能是嵌套循环的原因,这就是为什么在我的示例中每个三个字段都出现两次的原因。祝你好运! :-) - Furbeenator
1个回答

2

1
对于再次遇到此问题的任何人,此问题已在Django 1.6及更高版本中得到解决。请参见git diff https://github.com/django/django/commit/cafb266954e21dd55ddfa90597bcf02c022bcb7d - chhantyal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接