导入CSV需要太长时间

时间:2013-10-21 20:39:07

标签: python google-app-engine

问题

我正在撰写应用引擎卡拉OK目录应用。该应用程序非常简单:在第一个版本中,它提供了将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

注释

  • 在开发环境中,我尝试导入最多17,500条记录并且没有遇到崩溃
  • 首先,记录会快速创建和插入,但随着数据库增长到数千,创建和插入记录所花费的时间会增加到每条记录几秒钟。

如何加快导入操作?任何建议,提示或提示将不胜感激。

更新

我遵循了Murph的建议并使用KeyProperty将歌曲链接回目录。对于17,500条记录,结果大约需要4分20秒 - 这是一项巨大的进步。这意味着,我还没有完全理解NDB如何在App Engine中运行,我还有很长的路要走。

虽然有了很大改进,但4分钟以上仍然太长了。我现在正在研究Tim和Dave的建议,进一步缩短我的应用程序的响应时间。

3 个答案:

答案 0 :(得分:1)

在Google App Engine的数据存储区中,对实体组的写入限制为每秒1次写入。

由于您为每首歌曲指定了“父”键,因此它们都会在一个实体组中结束,这非常慢。

使用KeyProperty来跟踪这种关系是否可以接受?虽然数据可能会有更多的一致性问题,但速度会快得多。

答案 1 :(得分:1)

除了另一个答案:实体组,如果导入过程需要超过60秒,使用任务,那么你有10分钟的运行时间。

将csv存储为实体中的BlobProperty(如果压缩< 1MB)或GCS更大,然后启动从存储中检索CSV然后进行处理的任务。

答案 2 :(得分:1)

首先,蒂姆走在正确的轨道上。如果您无法在60秒内完成工作,请遵循任务。但如果你不能在10分钟内完成工作,请回到App Engine MapReduce,这将分配处理你的csv跨多个任务的工作。请参考demo program,其中包含您需要的部分内容。

对于开发时间缓慢,启动dev_appserver时是否使用--use_sqlite选项?

Murph触及你问题的另一部分。使用实体组,您可以对可以执行的插入数(每个实体组)进行速率限制。尝试使用单个父级插入17,500行并不能很好地工作。这将需要大约5个小时。

那么,你真的需要一致的阅读吗?如果这是一次性上传,你可以进行非祖先插入(将目录作为属性),然后稍等一下,使数据最终变得一致吗?这简化了查询。

如果你真的,绝对需要一致的读取,你可能需要在多个父键之间拆分你的写入。这会增加您的写入速度,但会使您的祖先查询更加复杂。