我试图了解在django中构建查询的最佳方法,以避免过多的数据库命中 这与问题类似:Django best practice with foreign key queries,但在查询中涉及更大的“深度”。
我的情况: models.py
class Bucket(models.Model):
categories = models.ManyToManyField('Category')
class Category(models.Model):
name = models.CharField(max_length=50)
class SubCategory(models.Model):
category = models.ForeignKey(Category)
class SubSubCategory(models.Model):
subcat = models.ForeignKey(SubCategory)
views.py
def showbucket(request, id):
bucket = Bucket.objects.prefetch_related('categories',).get(pk=id)
cats = bucket.categories.prefetch_related('subcategory_set__subsubcategory_set',)
return render_to_response('showbucket.html', locals(), context_instance=RequestContext(request))
及相关模板:
{% for c in cats %}
{{c}}
<ul>
{% for d in c.subcategory_set.all %}
<li>{{d}}</li>
<ul>
{% for e in d.subsubcategory_set.all %}
<li>{{e}}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
{% endfor %}
尽管使用了prefetch_related(),但每次评估前两个语句时,我似乎都在点击数据库,例如{%for c in cats%},(至少我相信阅读debug_toolbar)。我尝试过的其他方式最终得到了(C x D x E)数据库命中数。这是我使用预取,查询或模型本质上是错误的吗? Django访问具有“深度&gt; 1”的数据库对象的最佳方式是什么?
答案 0 :(得分:3)
改为使用select_related():
bucket = Bucket.objects.select_related('categories',).get(id=id)
cats = bucket.categories.select_related('subcategory_set__subsubcategory_set',)
答案 1 :(得分:0)
所以,我发现这里有几件事情发生了:
首先,我目前对select_related vs prefetch_related的理解:
select_related()遵循外键关系,导致更大的结果集,但意味着以后使用FK不需要额外的数据库命中。它仅限于FK和一对一的关系。
prefetch_related()对每个关系进行单独查找并在python中连接它们,并且意味着用于多对多,多对一,GenericRelation和GenericForeignKey。
通过这本书,我应该使用prefetch(),因为我没有“关注”外键。 这就是我理解的内容,但是我的模板似乎在评估模板中给定的for循环时引起了额外的查询,即使我添加了{with}标签的使用。
起初,我以为我发现了类似于this issue的东西,但是当我构建我的简化示例时,我无法复制。我使用调试工具栏切换到使用以下模板代码进行直接检查(在Karen Tracey使用Django跟踪SQL查询的文章中,我会链接但是链接限制):
{% with sql_queries|length as qcount %}
{{ qcount }} quer{{ qcount|pluralize:"y,ies" }}
{% for qdict in sql_queries %}
{{ qdict.sql }} ({{ qdict.time }} seconds)
{% endfor %}
{% endwith %}
使用这种方法,我只看到5个使用pre-fetch()的查询(带有debug_toolbar的7个),并且当使用select_related()(对于debug_toolbar使用+2)时,查询会线性增长,我认为这是预期的。 / p>
我很乐意接受任何其他建议/工具来处理这些类型的问题。