Django: очень медленный запуск Python миграция на связанных моделях - PullRequest
2 голосов
/ 06 февраля 2020

Я пытаюсь оптимизировать скорость миграции на большой таблице (250 тыс. Объектов). Цель состоит в том, чтобы добавить в каждую строку поле пользователя на основе пользователя объекта, связанного с этой строкой:

Я пытался использовать выражение F, но, к сожалению, django не разрешает в них отношения. Обратите внимание, что я в основном новичок в SQL:)

## models.py
class Band(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        default=None)
    ...

class Album(models.Model):
    band = models.ForeignKey(
        Band
        on_delete=models.CASCADE,
        null=True,
        default=None)

    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        default=None)
    ...

## 0035_album_add_user.py
def forwards_add_user(apps, schema_editor):
    Album = apps.get_model('band', 'Album')
    db_alias = schema_editor.connection.alias

    albums = Album.objects \
        .using(db_alias) \
        .filter(band__isnull=False) \
        .select_related('band', 'band__user')

    for each in albums:
        each.user = each.band.user

    Album.objects \
        .using(db_alias) \
        .bulk_update(albums, ['user'])

class Migration(migrations.Migration):
    dependencies = [ ... ]

    operations = [
        migrations.RunPython(forwards_add_user, reverse_add_user),
    ]

. В настоящее время эта миграция занимает один час на моем локальном компьютере со 100% использованием базы данных в течение всего времени. У меня лучший процессор, спасибо моей производственной базе данных, так что это меня очень беспокоит, отказ от производственной базы данных в течение часа на самом деле не вариант.

Я смотрю на два разных решения, о которых я понятия не имею о том, как выполнить sh: - оптимизировать код python, чтобы он работал быстрее; - снизить нагрузку на ЦП базы данных во время миграции, чтобы она оставалась доступной. Оба являются лучшим сценарием:)

Я использую Python3 .6.9 с Django2.2.9 и PostgreSQL10.6 на RDS в рабочей среде и Docker в локальной системе.

Спасибо!

1 Ответ

2 голосов
/ 06 февраля 2020

Используйте подзапрос для обновления поля, что-то похожее на следующее, так как вы не можете использовать функцию F () при обновлении таблиц присоединения

Album.objects.update(
    user=Subquery(
        Band.objects.filter(
            id=OuterRef('band')
        ).values('user')[:1]
    )
)
...