我需要在一个大的(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。
答案 0 :(得分:7)
确保settings.DEBUG
设置为False
。 DEBUG=True
填充内存,尤其是数据库密集型操作,因为它存储了在视图中发送到RDBMS的所有查询。
使用Django 1.8时,它不应该是必需的,因为现在存储了最多9000个查询的硬编码,而不是之前存储的无限数。
答案 1 :(得分:2)
欢迎来到Django的ORM。我认为这是一个固有的问题。
我也遇到过大型数据库,dumpdata,loaddata等问题。
你有两个选择。
停止尝试使用south并编写自己的ORM迁移。您可以在设置中拥有多个数据库定义。创建“旧”和“新”。将您自己的一次性迁移器从旧数据库写入新数据库。一旦经过测试和运行,最后一次运行它,然后切换数据库定义并重新启动Django。
向南撤消ORM并编写自己的SQL迁移。使用原始SQL将旧结构中的数据复制到新结构中。单独调试。如果它很好,最后运行它然后切换你的设置并重启Django。
不是南方或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)
如果您不需要对对象的完全访问权限,则可以始终在查询集上使用only
和values
或values_list
的组合。这应该有助于显着降低内存需求,但我不确定它是否足够。