Django移民被杀

时间:2016-01-17 21:05:13

标签: python django postgresql migration

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

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

  • 最初,一切都很好,但是在添加我的自定义代码之后,迁移开始花费很长时间(相对)运行 。大约10秒钟。
  • 有时会奏效。即。如果我从命令行运行十次迁移,有时会运行,有时会失败。

输出如下(应用程序名称已删除):

[web@dev myapp]$ ./manage.py migrate
Operations to perform:
  Apply all migrations: myapp1, myapp2, myapp3, myapp4
Running migrations:
Killed
  • 起初我以为是因为我使用RunPython运行Python函数,在删除其中一个字段之前复制两个字段之间的数据。该文档不鼓励将其用于PostgreSQL,但是有更好的方法吗?
  • 这里的业务场景是我有一个布尔字段,我需要切换到一组选项(CharField with options)。代码检查布尔值是否为true并为字符字段设置正确的值。我做了两次。第一次最终结束了工作,但我还没有在另一个数据库上测试它。

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

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),
    ]

我的想法:

  • 也许我在这里写的代码花了太长时间才能运行?数据库中的模型不到一百个,所以我不知道为什么fix_consulting函数需要这么长时间。

  • 如果我在fix_consulting的开头添加print语句,它们有时只会运行,并且会被杀死。按照目前的情况,我已经运行了6-8次并且每次都被杀死,但是在不同的地方

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

2 个答案:

答案 0 :(得分:8)

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

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

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

接下来,我建议尝试始终将从db返回的内容过滤到实际需要的内容(通过拼接或过滤)

答案 1 :(得分:0)

如果您模型的任何字段的大小都很大,那么问题可能是内存已用完。如果迁移计算不需要此字段,只需使用 defer()only() 将其省略。

例如要只加载必要的字段 locationcategory,您可以执行以下操作:

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() 来收紧从数据库加载的字段。