Как удалить 200 000 записей с помощью DJango?

Ситуация: У меня есть модель отношения 1-1, образец:

class User(models.Model):
    user_namme = models.CharField(max_length=40)
    type = models.CharField(max_length=255)
    created_at = models.DatetimeField()
    ...

class Book(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

У меня около 200 000 записей.

  • Язык: Python
  • Framework: Django
  • База данных: Postgres

Вопрос:

  • Как удалить 200 000 записей с минимальными затратами?

Решение, которое я пробовал:

user_ids = Users.objects.filter(type='sample', created_date__gte='2022-11-15 08:00', created_date__lt="2022-11-15 08:30").values_list('id',flat=True)[:200000] # Fetch 200,000 user ids. 
for i, _ in enumerate(user_ids[:: 1000]):
    with transaction.atomic():
        batch_start = i * self.batch_size
        batch_end = batch_start + self.batch_size
        _, deleted = Users.objects.filter(id__in=user_ids[batch_start,batch_end]
    

При таком решении мой сервер использует около:

  • 600MB CPU
  • 300MB RAM
  • Потребуется более 15 минут для завершения работы.

Интересно, есть ли у кого-нибудь лучшее решение?

По первым принципам, ничто не сравнится с сырым (Django query) SQL по скорости, потому что он работает ближе всего к базе данных!

cursor.execute("DELETE FROM DB WHERE Column = %s")

Или же вы можете сделать это следующим образом:

Variable = Model.objects.filter(variable=variable)

if Variable.exists():

    Variable.delete()

Спасибо всем. Я попробовал решение с помощью RawQuery

user_ids = Users.objects.filter(type='sample', created_date__gte='2022-11-15 08:00', created_date__lt="2022-11-15 08:30").values_list('id',flat=True)[:200000] # Fetch 200,000 user ids. 

for i in range(0, 3):
    user_ids_str = ""
    for user_id in user_ids.iterator(chunk_size=5000):
        user_ids_str += f"{user_id},"
    query = f"""
            DELETE FROM "user" WHERE "user"."id" IN ({user_ids_str});
            DELETE FROM "book" WHERE "user"."id" IN ({user_ids_str});
    """
    with transaction.atomic():
        with connection.cursor() as c:
            c.execute("SET statement_timeout = '10min';")
            c.execute(query)

Этот может удалить 600000 записей и занимает около 10 минут. А сервер использует около:

  • CPU: 50MB
  • RAM: 200MB
Вернуться на верх