2010-08-03 66 views
31

我正在使用Django的一個sqlite後端,並寫性能是一個問題。我可能會在某個階段畢業到一個「適當」的數據庫,但目前我堅持使用sqlite。我認爲我的寫入性能問題可能與我創建大量行有關,並且大概每次我鎖定,解鎖和同步磁盤上的數據庫。在Django中彙總save()?

如何將大量的save()調用集合到單個數據庫操作中?

+0

http://stackoverflow.com/questions/1136106/efficent-way-to-insert-thousands-of-records-into-a-table-sqlite-python-django – 2010-08-03 09:53:46

+0

@Tomasz - 感謝您的鏈接, @commit_manually裝飾器爲我提供了所需的性能改進。我已經把我的問題標記爲關閉,因爲我認爲另一個很好地覆蓋了它。 – kdt 2010-08-03 10:22:55

+0

你知道,你實際上可以關閉你的問題,而不是簡單地投票結束。 – 2010-08-03 12:41:51

回答

54

其實這樣做比較容易做,然後你就會想。您可以在Django中使用transactions。這些批量數據庫操作(特別是保存,插入和刪除)整合到一個操作中。我發現最容易使用的是commit_on_success。本質上,你將數據庫保存操作包裝到一個函數中,然後使用裝飾器commit_on_success

from django.db.transaction import commit_on_success 

@commit_on_success 
def lot_of_saves(queryset): 
    for item in queryset: 
     modify_item(item) 
     item.save() 

這將有巨大的速度增加。如果任何項目失敗,您還可以獲得回滾的好處。如果您有數百萬次保存操作,那麼您可能必須使用commit_manuallytransaction.commit()以塊形式提交它們,但我很少需要它。

希望幫助,

請問

+0

這幾乎是神奇的。我包裝了一個隨機函數,它創建了很多記錄,並且它在SQLite中立即變得快幾倍。 – alberge 2011-06-24 20:02:40

+32

對於那些現在運行此答案的用戶,現在不推薦使用'commit_on_success'。相反,用'atomic'替換它,這是新版本,並且將具有相同的魔法效果! – Pterosaur 2014-07-23 17:47:12

+7

'原子'參考:https://docs.djangoproject.com/zh/dev/topics/db/transactions/#django.db.transaction.atomic – Paolo 2016-06-15 14:28:47

1

「如何將大量save()調用聚合到單個數據庫操作中?」

你不需要。 Django已經爲你管理一個緩存。試圖通過保存措施來改善數據庫緩存。

「寫入性能問題可能與我要創建大量的行的事實」

正確的。

SQLite很慢。它就是這樣兒的。查詢比其他數據庫更快。寫入很慢。

考慮更嚴重的架構變更。您是否在Web事務中加載行(即批量上傳文件並從這些文件加載​​數據庫)?

如果您在網絡交易中進行批量加載,請停止。你需要做更聰明的事情。使用celery或使用其他一些「批次」工具在後臺執行加載。

我們試圖限制自己在Web事務中進行文件驗證,並在用戶不等待他們的HTML頁面時執行加載。

+1

雖然指出sqlite確實天生就是公平的由於它使用磁盤的方式而導致寫入緩慢,因此它不必是* this * slow:正如評論員所建議的那樣,我開始使用@commit_manually裝飾器並發現了一個非常實際的改進。 – kdt 2010-08-03 10:24:04

41

新的Django的1.6是atomic, a simple API to control DB transactions。從該文檔逐字拷貝:

原子可用既作爲decorator

from django.db import transaction 

@transaction.atomic 
def viewfunc(request): 
    # This code executes inside a transaction. 
    do_stuff() 

和作爲context manager

from django.db import transaction 

def viewfunc(request): 
    # This code executes in autocommit mode (Django's default). 
    do_stuff() 

    with transaction.atomic(): 
     # This code executes inside a transaction. 
     do_more_stuff() 

遺留django.db.transaction功能autocommit()commit_on_success(),和commit_manually()已過時,並且將在Django 1.8中刪除。