2009-09-09 18 views
2

我有一個Django視圖,它可以在循環中創建500-5000個新的數據庫插入。問題是,它真的很慢!我在Postgres 8.3上每分鐘獲得大約100個插入。我們曾經在較小的硬件(較小的EC2實例)上使用MySQL,並且從來沒有遇到過這些類型的速度問題。加速來自ORM的數據庫插入

詳情: Ubuntu 9.34上的Postgres 8.3。 服務器是EBS(ext3) - 11GB/20GB上帶有數據庫的「大型」Amazon EC2。

下面是一些我的postgresql.conf的 - 讓我知道,如果你需要更多的

​​

我的Python:從上

for k in kw: 
     k = k.lower() 
     p = ProfileKeyword(profile=self) 
     logging.debug(k) 
     p.keyword, created = Keyword.objects.get_or_create(keyword=k, defaults={'keyword':k,}) 
     if not created and ProfileKeyword.objects.filter(profile=self, keyword=p.keyword).count(): 
      #checking created is just a small optimization to save some database hits on new keywords 
      pass #duplicate entry 
     else: 
      p.save() 

一些輸出:

top - 16:56:22 up 21 days, 20:55, 4 users, load average: 0.99, 1.01, 0.94 
Tasks: 68 total, 1 running, 67 sleeping, 0 stopped, 0 zombie 
Cpu(s): 5.8%us, 0.2%sy, 0.0%ni, 90.5%id, 0.7%wa, 0.0%hi, 0.0%si, 2.8%st 
Mem: 15736360k total, 12527788k used, 3208572k free, 332188k buffers 
Swap:  0k total,  0k used,  0k free, 11322048k cached 

    PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND                                    
14767 postgres 25 0 4164m 117m 114m S 22 0.8 2:52.00 postgres                                    
    1 root  20 0 4024 700 592 S 0 0.0 0:01.09 init                                     
    2 root  RT 0  0 0 0 S 0 0.0 0:11.76 migration/0                                   
    3 root  34 19  0 0 0 S 0 0.0 0:00.00 ksoftirqd/0                                   
    4 root  RT 0  0 0 0 S 0 0.0 0:00.00 watchdog/0                                   
    5 root  10 -5  0 0 0 S 0 0.0 0:00.08 events/0                                    
    6 root  11 -5  0 0 0 S 0 0.0 0:00.00 khelper                                    
    7 root  10 -5  0 0 0 S 0 0.0 0:00.00 kthread                                    
    9 root  10 -5  0 0 0 S 0 0.0 0:00.00 xenwatch                                    
    10 root  10 -5  0 0 0 S 0 0.0 0:00.00 xenbus                                    
    18 root  RT -5  0 0 0 S 0 0.0 0:11.84 migration/1                                   
    19 root  34 19  0 0 0 S 0 0.0 0:00.01 ksoftirqd/1 

讓我知道是否有其他細節會有所幫助。

回答

3

首先,ORM操作總是比純SQL慢。我曾經給ORM代碼中的一個大型數據庫寫了一個更新,並將其設置爲正在運行,但是在幾個小時之後,它只完成了一小部分時間就退出了。用SQL重寫它之後,整件事情在不到一分鐘的時間裏就完成了。

其次,請記住,在這裏你的代碼是做多達四個獨立的數據庫操作,每行中的數據集 - 在get在get_or_create,可能還有create,過濾器上的count,最後save。這是很多數據庫訪問。

考慮到最多5000個對象不是很大,您應該能夠在開始時將整個數據集讀入內存。然後,您可以執行單個filter以一次性獲取所有現有的Keyword對象,從而在關鍵字get_or_create中節省大量查詢,並且避免了首先實例化重複的ProfileKeywords的需要。

+0

+1指出一次讀取所有內容如果可以的話更高效,並且每次都不需要額外的過濾器。 – 2009-09-09 19:03:16

+0

@Daniel Roseman:你可以擴展一下「然後你可以做一個過濾器來獲得所有現有的關鍵詞對象......」?我其實有數百萬個關鍵詞對象已經在數據庫中,所以我不想將它們全部讀入內存。我一次插入5000個新對象.... – erikcw 2009-09-16 01:13:46

+0

我最終使用Keyword.objects.filter(keyword__contains = ...)將相關關鍵字對象讀入內存。劇本現在運行不到10秒!我還添加了事務保存點.... – erikcw 2009-09-17 18:13:29

6

像這樣緩慢批量操作的一個常見原因是每個插入操作發生在其自己的事務中。如果你能讓所有這些事情在一筆交易中發生,它可能會更快。

+1

+1我的猜測也是。 @erikcw:嘗試通過http://docs.djangoproject.com/en/dev/topics/db/transactions/管理您的交易 – 2009-09-09 17:19:30

+0

這幾乎可以保證是答案。單次插入事務處理必須比在事務中執行多次插入操作慢。 – wlashell 2009-09-09 18:35:18