Эффективно создавать массивные записи базы данных?

Я пытаюсь создать объект Activty для большого (300 + за раз) списка объектов Inquiry. У меня есть один ModelForm, который отправляется назад, и мне нужно создать отдельные экземпляры и прикрепить их к Inquiry через GenericForeignKey. Позвольте получить код:

models.py:

class InquiryEntry(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField() 
    entry = generic.GenericForeignKey('content_type', 'object_id')

class Inquiry(models.Model):
    entries = models.ManyToManyField('InquiryEntry')
    # And many more fields.
    def add_entry(self, obj):
        entry = self.entries.create(entry=obj)
        self.save()
        return entry

class Activity(models.Model):  
    ts = models.DateTimeField(auto_now_add=True)                  
    due_date = models.DateField(auto_now=False)
    ## And many more fields.

views.py:

def bulk_create_activities(request):
    activity_form = ActivityForm()
    if request.method == "POST":
        activity_form = ActivityForm(request.POST)
        if activity_form.is_valid():    
            pks = [int(x) for x in request.POST.get('pks', '').split(',')]
            for inquiry in Inquiry.objects.filter(pk__in=pks):
                instance = ActivityForm(request.POST).save()
                inquiry.add_entry(instance)     
                inquiry.save()  

Я ищу способ вставить их в базу данных, желательно за один проход, чтобы запрос мог обрабатываться быстрее. Я предпочитаю не переходить на уровень базы данных, поскольку это приложение развертывается у нескольких поставщиков баз данных, но если это единственный способ продолжить работу, пусть будет так (примеры для MySQL и Postgres были бы замечательными).


Примечание. Я знаю, что в версии разработки есть bulk_create, но это из вопрос до тех пор, пока не будет стабильного выпуска.

Ответ 1

Попробовал ли вы просто включить for в конструкцию транзакции? Операции с фиксацией на успех могут привести к огромным ускорениям, потому что записи конкретно записываются на диск одновременно в массовом порядке, поэтому для каждого СУБД не нужно останавливаться на fsync().

Реализация транзакций в последних версиях django мгновенно, проверьте https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

Ответ 2

Боюсь, вам может понадобиться перейти к DB-API и использовать cursor.executemany(). Подробнее см. PEP 249.

Ответ 3

вы можете получить некоторые подсказки (в том числе для разных систем db), посмотрев на sql django для некоторых выборочных данных. запуск вашего сервера в режиме отладки, все запросы регистрируются. вы также можете проверить их через

>>> from django.db import connection
>>> connection.queries

Ответ 4

Взгляните на http://people.iola.dk/olau/python/bulkops.py

Он предоставляет функции insert_many и update_many, которые выполняют один запрос. Как отметил автор, вам нужно будет выполнить некоторую ручную ведение бухгалтерского учета в python для pks во многих отношениях, но как только вы их разработаете, вы можете просто выполнить пару insert_many на Inquiry и InquiryEntry.

Ответ 5

Это не делает ваше групповое действие более эффективным, но если Inquiry не нужно мгновенно реагировать на данные, представленные (я предполагаю, основываясь на имени модели), это звучит как идеальное задание для очереди задач, например, Celery.

Пользователь получит супер быстрый ответ, и ваши работники сельдерея могут хрустнуть на нем на досуге. Когда 1.4 стабилен, проверьте in_bulk:)

Мне также будет интересен массивный метод агностической базы данных, но в зависимости от вашей ситуации это может быть приемлемым решением.

Будет смотреть ответы здесь...