Каков наилучший способ обработки данных миграции DJANGO с более чем 500 тыс. записей для MYSQL

  • Вторая миграция создает два новых поля action_duplicate и status_duplicate
  • .
  • Вторая миграция копирует данные из полей action и status в два вновь созданных поля
  • .
def remove_foreign_keys_from_user_request(apps, schema_editor):
    UserRequests = apps.get_model("users", "UserRequest")

    for request_initiated in UserRequest.objects.all().select_related("action", "status"):
        request_initiated.action_duplicate = request_initiated.action.name
        request_initiated.status_duplicate = request_initiated.status.name
        request_initiated.save()
  • Третья миграция должна удалить/удалить старые поля action и status
  • .
  • Четвертая миграция должна переименовать новые дублирующие поля в старые удаленные поля. Решением здесь является удаление зависимости от статуса и действия, чтобы избежать ненужных запросов к базе данных, так как статус особенно будет только pending и completed

Мой вопрос касается второй миграции. Количество записей составляет от 300k до 600k записей, поэтому мне нужно знать более эффективный способ сделать это, чтобы не занимать всю доступную память. Примечание: База данных MySQL.

Уменьшенная версия модели UserRequest

class UserRequest(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    reference = models.CharField(max_length=50, null=True, blank=True)
    requester = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
    action = models.ForeignKey(Action, on_delete=models.CASCADE)
    action_duplicate = models.CharField(
        max_length=50, choices=((ACTION_A, ACTION_A), (ACTION_B, ACTION_B)), default=ACTION_A
    )
    status = models.ForeignKey(ProcessingStatus, on_delete=models.CASCADE)
    status_duplicate = models.CharField(
        max_length=50,
        choices=((PENDING, PENDING), (PROCESSED, PROCESSED)),
        default=PENDING,
    )

Вы можете работать с Subquery выражением [Django-doc], и делать обновление массово:

def remove_foreign_keys_from_user_request(apps, schema_editor):
    UserRequests = apps.get_model('users', 'UserRequests')
    Action = apps.get_user('users', 'Action')
    Status = apps.get_user('users', 'ProcessingStatus')
    UserRequests.objects.update(
        action_duplicate=Subquery(
            Action.objects.filter(
                pk=OuterRef('action_id')
            ).values('name')[:1]
        ),
        status_duplicate=Subquery(
            Status.objects.filter(
                pk=OuterRef('status_id')
            ).values('name')[:1]
        )
    )

При этом, похоже, то, что вы делаете, на самом деле является противоположностью нормализации базы данных [wiki]: обычно, если есть дублирующиеся данные, вы создаете дополнительную модель, где вы делаете одно Action/Status на значение, и таким образом предотвращаете наличие одного и того же значения action_duplicate/status_duplicate несколько раз в базе данных: это сделает базу данных больше, и ее труднее поддерживать.


Примечание: обычно модели Django присваивается сингулярное имя, поэтому UserRequest вместо UserRequests.

Вернуться на верх