我正在使用一个小树/图形包(django_dag),它为我的模型提供了一个多对多的子字段,它引用了它自己。基本结构可以显示为以下模型
#models
class Foo(FooBase):
class Meta:
abstract = True
children = models.ManyToManyField('self', symmetrical = False,
through = Bar)
class Bar():
parent = models.ForeignKey(Foo)
child = models.ForeignKey(Foo)
一切都很好,模型和包的所有功能。
FooBase
为模型添加了各种函数,包括递归查找Foo
的所有子项以及子项的子项等等。
我关心的是FooBase
中的以下功能:
def descendants_tree(self):
tree = {}
for f in self.children.all():
tree[f] = f.descendants_tree()
return tree
它输出类似{Foo1:{},Foo2:{Child_of_Foo2:{Child_of_Child_of_Foo2:{}}}},其中后代在嵌套字典中。
警报阅读器可能会注意到此方法为每个孩子调用一个新查询。 虽然这些db命中很快,但是当可能有50个以上的孩子时,它们可以快速加起来。最终,将有成千上万的db条目。现在,每个查询的平均值为0.6毫秒,行数几乎为2000。
是否有更有效的方法来执行此嵌套查询?
在我看来,事先做一个select_related()。all()会把它归结为一个查询但是这个问题在将来会有点麻烦。一个大的查询在什么时候比许多小查询更好或更差?
--- ---编辑
以下是我正在尝试使用select_related().all()
选项进行测试的内容,但它仍然会在每次迭代中进行测试:
all_foo = Foo.objects.select_related('children').all()
def loop(baz):
tree = {}
for f in all_foo.get(id = baz).children.all()
tree[f] = loop(f)
return tree
我认为children.all()
导致了点击。是否有另一种方法可以在不使用callable属性的情况下获取所有多对多孩子?
答案 0 :(得分:1)
您必须根据自己的情况在自己的环境中进行测试。通常建议使用select_related
,但是如果会有很多递归级别,那么一个大型查询通常比多个查询慢。
孩子的数量并不重要,递归的水平是最重要的。如果你做3个左右,select_related()
可能会更好,但远远超过这个可能会导致减速。插件作者可能这样做是为了允许多个级别的递归,因为只有少数几个才会真正受到伤害,而且这只是一些额外的查询。