优化 FOR 循环中的请求

Posted

技术标签:

【中文标题】优化 FOR 循环中的请求【英文标题】:Optimize request in the FOR loop 【发布时间】:2021-11-24 19:36:56 【问题描述】:

如何优化以下请求以消除循环?代码数是几百,所以我得到了几百个数据库查询,这是不可接受的。

n = 3
result = []
codes = Target.objects.filter(code__in=['ABC', 'CDE', ...])

for code in codes:
    result.append(Data.objects.select_related('target')
                              .filter(target__code=code)
                              .values('spec', 'spec_type')
                              .order_by('-spec')[:n])

型号:

class Data(models.Model):
    target = models.ForeignKey(Target)
    spec_type = models.CharField()
    spec = models.FloatField()

class Target(models.Model):
    code = models.TextField(db_index=True)

【问题讨论】:

应该是什么结果:当前您正在构建QuerySets 的列表。你想要一个“平面”的项目列表吗?对于Querysets的列表,可以做的优化不多。 我删除了一些将Querysets转换为dicts的逻辑,最终结果如下: [ 'ABC': ['spec': 'Spec 123', 'spec_type': '规格类型 A','spec':'规格 456','spec_type':'规格类型 B'],'CDE':...]。所以它是带有键“代码”和值的字典 - 两个字典的列表,它们是数据,由 Data.objects.... 查询检索。 【参考方案1】:

您不必将codes 检索为QuerySet 即可枚举。我们可以直接使用代码列表。

如果你想构造一个包含所有给定元素的QuerySet,你可以创建一个带有联合的QuerySet,它将获取这些对象。在这种情况下,可以使用.union(…) [Django-doc]:

codes = ['ABC', 'CDE']
n = 3
result = Data.objects.none().union(
    *[
      Data.objects.filter(target__code=code).values('spec', 'spec_type').order_by('-spec')[:n]
      for code in codes
    ],
    all=True
)

【讨论】:

【参考方案2】:

就像@Willem Van Onsem 所说,您不需要获取Target 对象的查询集,因为您似乎已经拥有所需的代码。只需将代码存储在变量中,然后您就可以使用该列表进行 django 查询。

codes = ['ABC', 'CDE', ...]

result = Data.objects.filter(target__code__in = codes)

此查询应返回所有Data 对象,其相关Target 对象的代码在列表codes 中。

【讨论】:

我首先尝试了这个查询,但由于某种原因,它只获取了第一个代码“ABC”的数据。 那么您确定您在代码列表中的值与您数据库中的值匹配吗?我已将此查询与我自己项目的模型一起使用,并且效果很好。 当然可以。一件有趣的事情:如果我在查询末尾省略 [:n] 切片,我会得到每个代码的所有数据,所以我猜这与子集的逻辑有关。 是的,如果您将[:n] 放在过滤器调用的末尾,那么结果将只有过滤器返回的查询集中的前 n 个条目。

以上是关于优化 FOR 循环中的请求的主要内容,如果未能解决你的问题,请参考以下文章

AFNetworking - 除了 for 循环中的最终请求外,其他所有请求均无响应

for 循环中的 objects.location 请求不会更新

forEach循环遍历请求接口

Promise循环执行多个请求

秒杀业务架构的优化

在 for 循环中发出请求时返回 JSON