2013-10-21 207 views
0

問題

我正在寫一個應用程序引擎卡拉OK目錄應用程序。該應用非常簡單:在第一個版本中,它提供了將CSV歌曲列表導入到目錄並顯示它們的功能。導入CSV時間太長

我遇到了CSV導入問題:在我的開發環境中導入17,500條記錄需要很長時間(14小時)。在生產環境中,它導入了大約1000條記錄,然後與代碼500一起墜毀。我正在瀏覽日誌,但沒有找到任何有用的線索。

守則

class Song(ndb.Model): 
    sid  = ndb.IntegerProperty() 
    title = ndb.StringProperty() 
    singer = ndb.StringProperty() 
    preview = ndb.StringProperty() 

    @classmethod 
    def new_from_csv_row(cls, row, parent_key): 
     song = Song(
       sid=int(row['sid']), 
       title=row['title'], 
       singer=row['singer'], 
       preview=row['preview'], 
       key=ndb.Key(Song, row['sid'], parent=parent_key)) 
     return song 

class CsvUpload(webapp2.RequestHandler): 
    def get(self): 
     # code omit for brevity 

    def post(self): 
     catalog = get_catalog(…) # retrieve old catalog or create new 

     # upfile is the contents of the uploaded file, not the filename 
     # because the form uses enctype="multipart/form-data" 
     upfile = self.request.get('upfile') 

     # Create the songs 
     csv_reader = csv.DictReader(StringIO(upfile)) 
     for row in csv_reader: 
      song = Song.new_from_csv_row(row, catalog.key) 
      song.put() 

     self.redirect('/upload') 

樣本數據

sid,title,singer,preview 
19459,Zoom,Commodores, 
19460,Zoot Suit Riot,Cherry Poppin Daddy, 
19247,You Are Not Alone,Michael Jackson,Another day has gone. I'm still all alone 

  • 在開發環境中,我試圖導入多達17500條記錄,並沒有遇到崩潰
  • 在首先,創建並快速插入記錄,但是a如果數據庫增長到數千,那麼創建和插入記錄所用的時間就會增加到每個記錄幾秒鐘。

如何加快導入操作?任何建議,提示或提示將不勝感激。

更新

我也跟着墨菲的建議和使用的KeyProperty一首歌鏈接回目錄。結果是大約4分20秒17,500條記錄 - 這是一個巨大的進步。這意味着,我並沒有完全理解NDB如何在App Engine中工作,而且我還有很長的路要學習。

儘管有了很大的改進,但4分鐘以上仍然過長。我現在正在研究Tim和Dave的建議,以進一步縮短我的應用程序的預期響應時間。

回答

1

在Google App Engine的數據存儲中,寫入實體組的寫入限制爲每秒寫入1次。

由於您爲每首歌曲指定了一個「父」鍵,它們都以一個非常緩慢的實體組結束。

僅僅使用KeyProperty來跟蹤這種關係是否可以接受?儘管數據可能存在更多一致性問題,但速度會更快。

+0

謝謝,Murph。我願意改變,但有點無知。請您詳細說明KeyProperty? –

+0

當然! ndb.KeyProperty()存儲數據存儲區密鑰。所以,如果你想添加一些東西到你的歌曲模型中,比如'catalog = ndb.KeyProperty()',然後當你創建歌曲時,你只需要在Song(...)構造函數中加入'catalog = parent_key'。然後你就可以拿一首歌並獲得它的父母 - 你只需要做somesong.catalog.get()。 – Murph

+0

我試試看。再一次感謝你。 –

1

除了其他答案:實體組以外,如果導入過程需要60秒以上的時間,請使用任務,然後運行10分鐘。

將csv作爲BlobProperty存儲在一個實體(如果壓縮爲< 1MB)或GCS爲較大的情況下,則啓動一個從存儲中檢索CSV的任務,然後執行處理。

+0

請參閱我的問題中的更新部分。謝謝。 –

1

首先,蒂姆在正確的軌道上。如果您在60秒內無法完成工作,請遵照任務。但是,如果你在10分鐘內無法完成工作,請回到App Engine MapReduce,該工作分配處理跨多個任務的csv的工作。請查閱demo program,其中有一些您需要的部分。

對於開發時緩慢,您是否在啓動dev_appserver時使用--use_sqlite選項?

墨菲觸動你的問題的其他部分。使用實體組,您可以限制您可以執行的插入次數(每個實體組)。試圖用單親父母插入17,500行是不行的。這將需要大約5個小時。

那麼,你真的需要一致的讀取嗎?如果這是一次性上傳,您可以執行非祖先插入(將目錄作爲屬性),然後等待一段時間以使數據最終一致?這簡化了查詢。

如果您確實需要一致的讀取,您可能需要將您的寫入分割爲多個父母鍵。這會增加您的寫入速度,但會使您的祖先查詢變得更加複雜。

+0

請參閱我的問題中的更新部分。謝謝。 –