Каков эффективный способ вставки тысяч записей в таблицу SQLite с помощью Django?

Я должен вставить 8000 + записей в базу данных SQLite с помощью ORM Django. Эта операция должна выполняться как cronjob примерно раз в минуту.
На данный момент я использую цикл for для итерации всех элементов, а затем вставляю их один за другим.
Пример:

for item in items:
    entry = Entry(a1=item.a1, a2=item.a2)
    entry.save()

что такое эффективный способ сделать это?

Edit: небольшое сравнение между двумя методами вставки.

без commit_manually декоратора (11245 записи):

nox@noxdevel marinetraffic]$ time python manage.py insrec             

real    1m50.288s
user    0m6.710s
sys     0m23.445s

использование commit_manually декоратора (11245 записей):

[nox@noxdevel marinetraffic]$ time python manage.py insrec                

real    0m18.464s
user    0m5.433s
sys     0m10.163s

Примечание: на тест скрипт также выполняет некоторые другие операции, помимо вставки в базу данных (загружает ZIP-файл, извлекает XML-файл из ZIP-архива, анализирует XML-файл), поэтому время, необходимое для выполнения, не обязательно представляет время, необходимое для вставки записей.

7 ответов


вы хотите проверить django.db.transaction.commit_manually.

http://docs.djangoproject.com/en/dev/topics/db/transactions/#django-db-transaction-commit-manually

так это будет что-то вроде:

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):
    ...
    for item in items:
        entry = Entry(a1=item.a1, a2=item.a2)
        entry.save()
    transaction.commit()

который будет совершать только один раз, а не при каждом save ().

в django 1.3 были введены контекстные менеджеры. Так что теперь вы можете использовать сделки.commit_on_success() в аналогичной путь:

from django.db import transaction

def viewfunc(request):
    ...
    with transaction.commit_on_success():
        for item in items:
            entry = Entry(a1=item.a1, a2=item.a2)
            entry.save()

в django 1.4,bulk_create был добавлен, что позволяет создавать списки объектов модели, а затем фиксировать их все сразу.

Примечание метод save не будет вызываться при использовании bulk create.

>>> Entry.objects.bulk_create([
...     Entry(headline="Django 1.0 Released"),
...     Entry(headline="Django 1.1 Announced"),
...     Entry(headline="Breaking: Django is awesome")
... ])

в django 1.6,сделки.атомный был введен, предназначенный для замены теперь устаревших функций commit_on_success и commit_manually.

от Джанго документация по atomic:

atomic можно использовать как в качестве декоратора:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

и как менеджер контекста:

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

массовое создание доступно в Django 1.4:

https://django.readthedocs.io/en/1.4/ref/models/querysets.html#bulk-create


посмотреть этой. Он предназначен для использования вне коробки только с MySQL, но есть указатели на то, что делать для других баз данных.


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


вы должны проверить DSE. Я написал DSE для решения таких проблем (массивная вставка или обновления ). Использование django orm-это тупик, вы должны сделать это в простом SQL, и DSE позаботится о многом из этого для вас.

Томас


чтобы ответить на вопрос, особенно в отношении SQLite, как было задано, в то время как я только что подтвердил, что bulk_create действительно обеспечивает огромное ускорение, существует ограничение с SQLite: "по умолчанию создается все объекты в одном пакете, за исключением SQLite, где по умолчанию используется максимум 999 переменных на запрос."

цитируемый материал из документов - - - A-IV предоставил ссылку.

Что я должен добавить это этот djangosnippets запись alpar также, кажется, работает для меня. Это небольшая обертка, которая разбивает большой пакет, который вы хотите обработать на меньшие пакеты, управляя пределом переменных 999.


Я рекомендую использовать простой SQL (не ORM) вы можете вставить несколько строк с одной вставкой:

insert into A select from B;

на выберите из B часть вашего sql может быть настолько сложной, насколько вы хотите, чтобы получить, пока результаты соответствуют столбцам в таблице A, и нет конфликтов ограничений.