首页 > 解决方案 > Django prefetch_related 似乎无法按预期工作

问题描述

描述

有一个Foo具有 ForeignKey 字段的模型bar

class Foo(models.Model):
  ...
  bar = models.ManyToManyField('bar.Bar', related_name='some_bar')
  ...

还有返回其字段的方法,Foo包括:get_config()bar

def get_config(self):
  return {
    ...
    'bar': map(lambda x: x.get_config(), self.bar.all())
    ...

现在数据库中有 10,000 行Foo。也有一些Bar行。

尝试检索大约 10,000 条数据,Foo包括嵌套Bar数据:

query = Foo.objects.all().prefetch_related('bar')
return [obj.get_config() for obj in query]

问题

查询执行大约 6 秒。如果没有bar字段 - 只有 400 毫秒。

预取似乎无法完全工作bar.get_config()似乎在每个迭代步骤中都会命中数据库。它应该简单地加载所有Bar对象一次并从该条查询中获取配置以填充每个foo配置。

想法

如果使用iterator()forfor循环,调用几乎停止并需要几十秒:[obj.get_config() for obj in query.iterator()]

标签: djangodjango-modelsdjango-queryset

解决方案


prefetch_related正在工作。Django使用包含 WHERE 子句和of allBar的单个 SELECT预取。这个具有 10k ids 的 SELECT 比 10k SELECTS 快得多,但比没有任何过滤器的单个 SELECT 慢得多。idsFoo


推荐阅读