2013-03-20 46 views
0

我想了解在django中構建查詢以避免過多數據庫命中的最佳方法。
這與問題類似:Django best practice with foreign key queries,但在查詢中涉及更大的「深度」。django最佳做法查詢外鍵

我的情況: 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以「深度> 1」的方式訪問數據庫對象的最佳方式是什麼?

回答

0

所以,我發現有幾件事情會在這裏:

首先,我目前的理解上select_related VS prefetch_related:

select_related()遵循外鍵關係,導致更大的結果集,但意味着稍後使用F K不需要額外的數據庫命中。它僅限於FK和一對一關係。

prefetch_related()爲每個關係執行單獨的查找並將它們連接到python中,並且可以用於多對多,多對一以及GenericRelation和GenericForeignKey。

通過這本書,我應該使用prefetch(),因爲我並沒有'追隨'外鍵。 這就是我所理解的,但是我的模板似乎在評估模板中給定的循環時會引起額外的查詢,即使我添加了{with}標籤的使用。

起初,我以爲我發現了類似於this issue的東西,但是當我構建我的簡化示例時,我無法複製。我使用的調試工具欄直接使用下面的模板代碼檢查切換(文章跟蹤SQL查詢使用Django的卡倫特蕾西的請求,我會聯繫,但我鏈路有限):

{% with sql_queries|length as qcount %} 
{{ qcount }} quer{{ qcount|pluralize:"y,ies" }} 
{% for qdict in sql_queries %} 
{{ qdict.sql }} ({{ qdict.time }} seconds) 
{% endfor %} 
{% endwith %} 

使用此方法,我只看到使用pre-fetch()(7 with debug_toolbar)的5個查詢,並且在使用select_related()(使用+2作爲debug_toolbar)時查詢會線性增長,我相信這是預期的。

我很樂意接受任何其他建議/工具來解決這些類型的問題。