Каков эффективный способ вставки тысяч записей в таблицу 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, и нет конфликтов ограничений.