2009-12-28 64 views
10

上午建立了一項服務,需要維護一些案例跟蹤系統。這裏是我們的模型:django查詢具有多個外鍵的模型的性能?

class Incident(models.Model):  
    title = models.CharField(max_length=128) 
    category = models.ForeignKey(Category) 
    status = models.ForeignKey(Status)  
    severity = models.ForeignKey(Severity) 
    owned_by = models.ForeignKey(User, related_name="owned_by", null=True, blank=True) 
    next_action = models.ForeignKey(IncidentAction)  
    created_date = models.DateTimeField() 
    created_by = models.ForeignKey(User, related_name="opened_by")  
    last_edit_date = models.DateTimeField(null=True, blank=True) 
    last_edit_by = models.ForeignKey(User, related_name="last_edit_by", null=True, blank=True)   
    closed_date = models.DateTimeField(null=True, blank=True) 
    closed_by = models.ForeignKey(User, related_name="Closed by", null=True, blank=True) 

因爲有很多外鍵被拉進這個模型,它會引起有趣的sql查詢。我們一直在使用djblets data grid和django調試工具欄作爲試用版,並且在每次爲使用外鍵的視圖添加新列時都會遇到大量查詢時感到震驚,它基本上實現了這種類型的查詢工作流:

#prepare the grid 
select * from incident_table; 
#render each row 
for each row in incident table 
    for each column that is a foreign key select row from foreign table with id 

它做一個額外的選擇查詢一行,試圖拉屬性的外鍵的每一列。

我在想這是django及其ORM關於從外鍵模型拉入屬性的普遍問題。作爲測試,我放棄了數據網格,併爲查詢集做了一個簡單的屬性列表,並以類似的方式看到查詢膨脹起來。

我們希望通過大量的用戶訪問模型來擴展這個範圍。作爲比較,我在User模型中做了一個類似的視圖,它的完整顯示只是使用一個查詢完成的,因爲如果您只從給定模型中拖出字段,則不會爲每個額外列創建額外的數據庫命中。

我們嘗試了一些優化爲:

  • django-orm-cache:似乎並不
  • django-caching使用Django 1.0.4工作:這非常適用於高速緩存經常查詢模型
  • 視圖級緩存與memcached
  • 編輯:使用select_related()可以通過沒有往返回數據庫的方式來加速模板渲染,但它看起來好像它遵循外鍵只是一個使用每個外鍵的單個查詢的原始查詢集的時間頭。似乎提前提出了多數據庫查詢命中。

但也有我們正在徵求羣衆的智慧上的一些更深層的問題:與國外萬噸鍵

,所提出的緩存和關注外鍵關聯的問題

回答

11

select_related()是正確的解決方案;你錯了它應該如何工作。我認爲如果您仍然在指定的FK中獲得多個查詢,則不會正確使用select_related。快速記錄一個Python會話(Studio有一個FK這裏django.auth.user):

>>> from django.db import connection 
>>> studios = Studio.objects.all().select_related('user') 
>>> for studio in studios: 
>>>  print studio.user.email 
>>>   
[email protected] 
[email protected] 
>>> len(connection.queries) 
1 

所以,我工作室的對象(2在我的測試DB)的列表,並得到了用戶的每一個一個SQL查詢。沒有select_related()調用,它需要三個查詢。

請注意,select_related doesn't handle many-to-many relationships - 儘管我認爲您可以手動查詢m2m的中間表,以便在不需要額外查詢的情況下沿着這些FK的任一方向執行操作,只要您可以從中間對象啓動您的查詢集即可。也許這就是抓住你的東西?你只指定了FK關係,而不是m2ms,所以我給出了一個簡單的例子。

+0

啊,是的。我站在非常糾正 - 看起來像datagrid實際上忽略提供的查詢集提供的任何優化,並執行其自己的查找。使用您的示例對我的模型進行獨立測試,使得select_related()的優勢如日清晰。謝謝! – dmyung 2009-12-29 19:23:32