【发布时间】:2017-10-02 07:52:24
【问题描述】:
使用: Django 1.11、Postgres 9.6
我需要优化 Django ORM 查询以供 Django Rest 框架使用。查询必须返回符合以下条件的记录:
- 匹配
target字段中的 ID 列表 - 将结果集限制为
sourceID 在集中出现多次的记录。
当前的方法是使用annotate 和Count 创建一个子查询,但是添加到分页的每个请求背后的处理量意味着它导致超时或非常缓慢的行为的应用程序。
如果服务器上的 Postgres 有什么可以作为原始查询完成的,我可以接受。
型号:
class Relationship(models.Model):
id = models.AutoField(primary_key=True)
source = models.BigIntegerField(db_index=True)
target = models.BigIntegerField(db_index=True)
查看sn-p:
match_list = [123, 456, 789] # dummy data for example
queryset = Relationship.objects.filter(target__in=match_list)
sub_queryset = (Relationship.objects.filter(target__in=_match_list)
.values('source')
.annotate(source_count=Count("source"))
.filter(source_count__gt=1)
)
sub_ids = [i["source"] for i in sub_queryset]
queryset = (queryset.filter(source__in=sub_ids)
)
API 将目标 ID 列表作为参数,并以连接到该目标的所有 source ID 列表进行响应。但是,我正在过滤查询集以仅返回连接到两个或多个 targets 的 source 记录。
作为背景,生成的查询集将由 Django Rest Framework 提供服务,它目前正在导致超时,因为请求越多,请求越长
注意:我把它放在 SO 上是因为它会导致我的请求超时并因此导致错误。我知道我可以延长超时时间,但宁愿优化查询。我考虑过 CodeReview,但觉得这更合适。
编辑 1:按照 @albar 的建议,它目前是一个单独的子查询,因为 annotate / Count 操作仅在返回值而不是完整记录时才有效
【问题讨论】:
-
可以像在目标和源上添加索引一样简单。
-
谢谢@e4c5,好点,但已经解决了 - 我在两个字段上都有索引(参见模型 - “db_index=True”)所以我相信这是
annotate/Count聚合步骤。 -
我真的不明白你的查询逻辑,以及为什么有那么多步骤。我认为您想要的查询很简单:
Relationship.objects.filter(target__in=_match_list).annotate(source_count=Count("source")).filter(source_count__gt=1). -
@albar 我最初尝试过这种方法,但注释仅适用于单个记录,因此
source_count值永远不会超过 1。我必须执行 .values操作才能启用整个结果集的聚合。我认为答案可能在于做一个子查询而不是多个查询,但我在这方面还没有太多经验。 -
@Phil Sheard 好的,我现在明白了。不容易……
标签: python django postgresql