Django 迁移被杀死

Django migration being killed

我对 Django 很有信心,但直到最近才主要依赖生成的迁移。我写了一个小的自定义迁移,在我的 CI 开始抱怨超时后不久,它最终与部署期间从 Django 的迁移有关。

起初,我能够解决这个问题,但我不知道我做了什么(如果有的话)来修复它。这个问题似乎与我为特定迁移输入的一些自定义代码有关。这是我所知道的:

输出如下(app名称被删掉):

[web@dev myapp]$ ./manage.py migrate
Operations to perform:
  Apply all migrations: myapp1, myapp2, myapp3, myapp4
Running migrations:
Killed

这是迁移(删除了应用名称):

from __future__ import unicode_literals

from django.db import migrations

def fix_consulting(apps, schema_editor):
    my_model = apps.get_model("myapp", "MyModel")
    for m in my_model._default_manager.all():
        if m.consulting:
            m.detail = "CONSLT"
            m.save()


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0024_auto_20160117_1113'),
    ]

    operations = [
        migrations.RunPython(fix_consulting,atomic=False),
    ]

我的想法:

其他信息: - 使用 Django 1.9 - 使用 PostgreSQL 9.4.4 - 错误主要发生在 CentOS 上,但也有 OSX

我认为您的问题是由使用 all 时可能需要缓存的数据量引起的,因为此 returns 对象的所有实例,因此您可以对在返回对象之前更改数据库级别,因为您随后只需要更改字段的值,您也可以在数据库级别上执行此操作。总之,这会将您的代码更改为以下内容。

def fix_consulting(apps, schema_editor):
    my_model = apps.get_model("myapp", "MyModel")
    my_model._default_manager.filter(consulting=True).update(detail="CONSLT")

这将内存管理责任放在数据库上,这似乎已经解决了您的问题。

展望未来,我建议尝试始终过滤从数据库返回的内容,仅保留实际需要的内容(通过拼接或过滤)

如果您模型的任何字段都很大,那么问题可能出在内存用完了。如果迁移计算不需要此字段,只需使用 defer()only().

将其省略

例如要 只加载必要的字段 位置 类别 你可以这样做:

for item in Item.objects.only('location', 'category').all()
    Item.objects.filter(pk=item.pk).update(location=category.default_location)

背景:

我在 Google 计算 VM 上遇到了类似的问题 - 当 运行 在大型数据库上时,我的 Django 迁移被终止。我发现不仅 CPU 使用率激增,而且内存和内存交换导致大量交换磁盘 I/O。

我尝试了 Sayse 的解决方案(从 save() 切换到 update()),虽然它确实有助于加快我的(较小的)测试数据库的速度,但在主生产数据库上迁移仍然失败。

最终,我意识到由于我模型中的一个特定 json 字段非常大,内存已用完。这个字段对于处理迁移来说是不必要的,所以我只是通过使用 only().

来加强从数据库加载的字段