Каков наилучший способ обработки данных миграции 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