django - 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()]
解决方案
prefetch_related
正在工作。Django使用包含 WHERE 子句和of allBar
的单个 SELECT预取。这个具有 10k ids 的 SELECT 比 10k SELECTS 快得多,但比没有任何过滤器的单个 SELECT 慢得多。ids
Foo
推荐阅读
- excel - CEILING 功能 - 舍入到下一个偶数
- visual-studio-code - 有什么方法可以通过 Settings Sync 在关闭时自动更新 VSCode 设置?
- php - 如何防止 Laravel Blade 剥离字母数字字符串?
- javascript - Jquery从循环元素的父级获取类列表
- flutter - 在颤振中实现材料可扩展输入芯片的最佳方法?
- .net - EPPlus 返回数字而不是日期/字符串
- php - 如何跟踪 IPv4 地址以防止多选?
- sql - 如何在不使用 id 键的情况下“压缩”多个嵌套的 JSON 数组?
- python - 在对 epsilon 使用线性退火的 epsilon 贪心策略时测量情节奖励
- hybris - 使用 ImpEx 跨不同环境的动态 URL