Эффективно создавать массовые записи в базе данных? - PullRequest
10 голосов
/ 28 октября 2011

Я пытаюсь создать объект 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, но об этом не может быть и до стабильной версии.

Ответы [ 5 ]

3 голосов
/ 30 октября 2011

Вы пытались просто заключить свой for в конструкцию транзакции?Транзакции, связанные с успешным выполнением, могут значительно увеличить скорость, поскольку записи сразу записываются на диск сразу, поэтому СУБД не нужно останавливаться для fsync () после каждого элемента.последние версии django snappy, проверьте https://docs.djangoproject.com/en/dev/topics/db/transactions/#controlling-transaction-management-in-views

1 голос
/ 04 ноября 2011

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

0 голосов
/ 03 ноября 2011

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

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

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

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

0 голосов
/ 01 ноября 2011

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

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

0 голосов
/ 01 ноября 2011

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

>>> from django.db import connection
>>> connection.queries
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...