在大型django表上进行高效的数据迁移

时间:2011-06-07 21:35:43

标签: python django performance django-models django-south

我需要在一个大的(5米行)django表中添加一个新列。我有一个南schemamigration创建新列。现在我正在编写一个datamigration脚本来填充新列。看起来像这样。 (如果您不熟悉南迁移,只需忽略模型名称前面的orm.。)

print "Migrating %s articles." % orm.Article.objects.count()
cnt = 0
for article in orm.Article.objects.iterator():            
    if cnt % 500 == 0:
        print "    %s done so far" % cnt
    # article.newfield = calculate_newfield(article)
    article.save()
    cnt += 1

我从objects.all切换到objects.iterator以减少内存需求。但是当我运行这个脚本时,某些东西仍在咀嚼着巨大的内存。即使上面注释了实际有用的行,脚本仍然会增长到使用10 GB以上的ram,然后才能在表格中走得太远而且我放弃了它。

似乎某些东西在内存中持有这些对象。我该如何运行它,这不是记忆猪?

FWIW,我使用的是python 2.6,django 1.2.1,南0.7.2,mysql 5.1。

5 个答案:

答案 0 :(得分:7)

确保settings.DEBUG设置为FalseDEBUG=True填充内存,尤其是数据库密集型操作,因为它存储了在视图中发送到RDBMS的所有查询。

使用Django 1.8时,它不应该是必需的,因为现在存储了最多9000个查询的硬编码,而不是之前存储的无限数。

答案 1 :(得分:2)

欢迎来到Django的ORM。我认为这是一个固有的问题。

我也遇到过大型数据库,dumpdata,loaddata等问题。

你有两个选择。

  1. 停止尝试使用south并编写自己的ORM迁移。您可以在设置中拥有多个数据库定义。创建“旧”和“新”。将您自己的一次性迁移器从旧数据库写入新数据库。一旦经过测试和运行,最后一次运行它,然后切换数据库定义并重新启动Django。

  2. 向南撤消ORM并编写自己的SQL迁移。使用原始SQL将旧结构中的数据复制到新结构中。单独调试。如果它很好,最后运行它然后切换你的设置并重启Django。

  3. 不是南方或ORM特别糟糕。但是,对于大型数据库中的批量处理,它们会在内存中缓存太多。

答案 2 :(得分:2)

orm.Article.objects.iterator()

这会运行整个查询并将结果保存在内存中吗?或者一次从数据库中获取一行?

我猜它一下子就完成了。看看是否可以使用以递增方式提取数据的数据库游标替换该循环:

例如:http://docs.python.org/library/sqlite3.html#sqlite3.Cursor.fetchmany

db = blah.connect("host='%s' dbname='%s' user='%s' password='%s'" % ...
new, old = db.cursor(), db.cursor()
old.execute("""
    SELECT  *
    FROM    whatever
""")
for row in old.fetchmany(size=500):
    (col1, col2, col3...) = row
    new = db.cursor()
    new.execute("""
        INSERT INTO yourtable (
            col1, col2, col3...)
        VALUES (
            %s, %s, %s, %s, %s)
        """,(col1, col2, col3,...))
new.close()
old.close()

会很慢。我从我的独立迁移脚本中删除了这个ymmv。

fetchmany是标准的(PEP249)。我还没完成你正在寻找的东西,所以从这个样本中还有一些工作要做:我没有循环遍历循环 - 要完成500套 - 所以你需要解决这个问题为了你自己。

答案 3 :(得分:2)

或者,如果您在原位创建实现基本结果集大小限制的原始查询会发生什么?

la:https://docs.djangoproject.com/en/1.3/topics/db/sql/#index-lookups

while min < rowcount:
  min += 500
  max = min + 500
  articles = Article.objects.raw('SELECT * from article where id > %s and id < %s' % (min, max))
  for old_article in articles:
    # create the new article
    article.save()

答案 4 :(得分:1)

如果您不需要对对象的完全访问权限,则可以始终在查询集上使用onlyvaluesvalues_list的组合。这应该有助于显着降低内存需求,但我不确定它是否足够。