2013-03-15 64 views
2

我有一個Django(1.4.2)的數據模型,像這樣:優化訪問從select_for_update記錄

class CoreData(models.Model): 
    cdid = models.AutoField(primary_key=True,editable=False) 
    atr1 = # whatever 
    atr2 = # whatever 

class EnvironData(models.Model): 
    cdid = models.ForeignKey(CoreData) 
    # etc 

class TransactionData(models.Model): 
    edid = models.ForeignKey(EnvironData) 
    # etc 

我需要有一個原子事務,其中我更新etc交易數據:

tdo = TransactionData.objects.select_for_update().get(etc=criteria) 
# process transaction 
# modify tdo object 
tdo.save() 

到目前爲止,這麼好。但是,在process transaction的過程中,我需要檢查CoreData.atr1CoreData.atr2

如果我通過tdo.edid.cdid.atr{1,2}訪問那些,那麼我的理解是我將有一個額外的讀取數據庫查詢,因爲Django獲取缺失的數據。 (說實話,我不是100%肯定這只是一個;也可能是兩個 - 甚至六個,但我會懷疑這一點)。

另一方面,如果我結合select_related()select_for_update()我不會只鎖定不需要(不應該)鎖定的數據,我還會爲tdo.save()創建開銷。

第三種方法可能是通過獨立查詢獲取數據(與tdo無關),如果使用select_related(),將保證是單個數據庫查詢。另外,它可以使用values()

我認爲最後一種方法是最有效的,因爲查詢可以從EnvironData對象開始,該對象的edid已經作爲tdo.edid_id

我的觀點是否合理?有更好的方法嗎?

更新:這是完全沒關係訪問tdo.edid.cdid.atr{1,2}獨立,甚至,他們可以在交易過程中發生變化,因爲它們是相互獨立的,它不要求他們保持整個交易的價值。 (謝謝@Uszy Wieloryba)

+1

你最終做了什麼?我遇到過類似的情況,當我嘗試在'select_related'中使用'select_for_update'時,我在Postgres中遇到了一個錯誤,更不用說我也擔心這種性能(鎖定是我最需要的廣泛使用的功能)...這是棘手的東西:/ – orokusaki 2013-05-02 16:51:25

+0

@orokusaki是的,這是_is_棘手的東西。我必須承認我還沒有優化它,所以生活在額外的數據庫中,這不是性能問題。我從來不喜歡'select_related' /'select_for_update'方法,感謝您的反饋。那麼看起來應該使用最後一種方法。你試過了嗎? – 2013-05-02 18:07:25

+0

我還沒有。我的想法:忘記表現並努力簡化。如果它的N + 1問題(選擇相關),這是一個大問題,但如果它只有3-5個額外的查詢,我不會汗流it背。我寧願在給定的視圖中單獨選擇每條記錄進行更新,而不是在精神開銷「我必須記住在更新postgres時測試它」等等,如果它成爲真正的數據庫問題,另一個(更好?)解決方案可能是使用cache.add(...)來鎖定記錄。谷歌「使用memcached鎖定」。 – orokusaki 2013-05-02 22:42:54

回答

0

如果您的# process transaction取決於CoreData.atr1CoreData.atr2,也許他們應該被鎖定。

+0

你提到這種可能性是正確的。可能存在競爭條件,使得事務代碼看到不一致的狀態並失敗。有趣的是,這兩者是彼此獨立的,只要在交易過程中的任何時間點檢查他們每個人是否滿足特定標準即可。無可否認,總體而言,情況並非總是如此。 – 2013-03-15 09:41:25