我正在使用一個小樹/圖包(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個以上的孩子時,它們可以快速加起來。最終,將會有數以萬計的數據庫條目。現在,每個查詢平均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()
導致命中。是否有另一種方法可以在不使用可調用屬性的情況下獲得所有多對多兒童?
感謝您的信息。一般來說,大多數孩子只會有1-2級的遞歸,而有些則會有3-4級。我不知道這是否合情合理,但要與家庭模式保持一致:一位「父母」可能有30個孩子,10個孫子女和5個曾孫。數據比較深。現在我正在嘗試使用'all()'查詢進行比較。 –
如果是這種情況,在你的情況下使用'select_related()'可能會更有意義。 –
我只是想調整我的循環,它仍然在爲每個迭代做一個命中,而不是使用'cached'select_related()'查詢,所以我沒有做正確的事 –