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

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

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

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

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

Без commit_manually decorator (11245 записей):

[email protected] marinetraffic]$ time python manage.py insrec             

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

Использование commit_manual decorator (11245 записей):

[[email protected] marinetraffic]$ time python manage.py insrec                

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

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

Ответ 1

Вы хотите проверить 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()

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

В django 1.3 были введены контекстные менеджеры. Итак, теперь вы можете использовать transaction.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, что позволяет создавать списки ваших объектов модели и затем совершать их все сразу.

ПРИМЕЧАНИЕ метод сохранения не будет вызываться при использовании массового создания.

>>> 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 был введен transaction.atomic, предназначенный для замены ныне устаревших функций commit_on_success и commit_manually.

из документации django для атома:

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

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 default).
    do_stuff()

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

Томас

Ответ 6

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

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

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

Ответ 7

prod_name = request.GET.getlist('prod_name []', '') prod_qty = request.GET.getlist('prod_qty []', '') prod_price = request.GET.getlist('prod_price []', '' ) я = 0 while (i

 # this is checking the variable, if variable is null so fill the varable value in database
 if p_n != "" and p_q != "" and p_p != "":
 prod_tab = Products(product_name=p_n, product_qty=p_q, product_price=p_p, customer_id=custo_id)
 prod_tab.save()
 i=i+1

Ответ 8

def order(request):    
    if request.method=="GET":
        # get the value from html page
        cust_name = request.GET.get('cust_name', '')
        cust_cont = request.GET.get('cust_cont', '')
        pincode = request.GET.get('pincode', '')
        city_name = request.GET.get('city_name', '')
        state = request.GET.get('state', '')
        contry = request.GET.get('contry', '')
        gender = request.GET.get('gender', '')
        paid_amt = request.GET.get('paid_amt', '')
        due_amt = request.GET.get('due_amt', '')
        order_date = request.GET.get('order_date', '')
        prod_name = request.GET.getlist('prod_name[]', '')
        prod_qty = request.GET.getlist('prod_qty[]', '')
        prod_price = request.GET.getlist('prod_price[]', '')

        # insert customer information into customer table
        try:
            # Insert Data into customer table
            cust_tab = Customer(customer_name=cust_name, customer_contact=cust_cont, gender=gender, city_name=city_name, pincode=pincode, state_name=state, contry_name=contry)
            cust_tab.save()
            # Retrive Id from customer table
            custo_id = Customer.objects.values_list('customer_id').last()   #It is return Tuple as result from Queryset
            custo_id = int(custo_id[0]) #It is convert the Tuple in INT
            # Insert Data into Order table
            order_tab = Orders(order_date=order_date, paid_amt=paid_amt, due_amt=due_amt, customer_id=custo_id)
            order_tab.save()
            # Insert Data into Products table
            # insert multiple data at a one time from djanog using while loop
            i=0
            while(i<len(prod_name)):
                p_n = prod_name[i]
                p_q = prod_qty[i]
                p_p = prod_price[i]

                # this is checking the variable, if variable is null so fill the varable value in database
                if p_n != "" and p_q != "" and p_p != "":
                    prod_tab = Products(product_name=p_n, product_qty=p_q, product_price=p_p, customer_id=custo_id)
                    prod_tab.save()
                i=i+1

            return HttpResponse('Your Record Has been Saved')
        except Exception as e:
            return HttpResponse(e)     

    return render(request, 'invoice_system/order.html')

Ответ 9

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

insert into A select from B;

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

Ответ 10

def order(request):    
    if request.method=="GET":
        cust_name = request.GET.get('cust_name', '')
        cust_cont = request.GET.get('cust_cont', '')
        pincode = request.GET.get('pincode', '')
        city_name = request.GET.get('city_name', '')
        state = request.GET.get('state', '')
        contry = request.GET.get('contry', '')
        gender = request.GET.get('gender', '')
        paid_amt = request.GET.get('paid_amt', '')
        due_amt = request.GET.get('due_amt', '')
        order_date = request.GET.get('order_date', '')
        print(order_date)
        prod_name = request.GET.getlist('prod_name[]', '')
        prod_qty = request.GET.getlist('prod_qty[]', '')
        prod_price = request.GET.getlist('prod_price[]', '')
        print(prod_name)
        print(prod_qty)
        print(prod_price)
        # insert customer information into customer table
        try:
            # Insert Data into customer table
            cust_tab = Customer(customer_name=cust_name, customer_contact=cust_cont, gender=gender, city_name=city_name, pincode=pincode, state_name=state, contry_name=contry)
            cust_tab.save()
            # Retrive Id from customer table
            custo_id = Customer.objects.values_list('customer_id').last()   #It is return
Tuple as result from Queryset
            custo_id = int(custo_id[0]) #It is convert the Tuple in INT
            # Insert Data into Order table
            order_tab = Orders(order_date=order_date, paid_amt=paid_amt, due_amt=due_amt, customer_id=custo_id)
            order_tab.save()
            # Insert Data into Products table
            # insert multiple data at a one time from djanog using while loop
            i=0
            while(i<len(prod_name)):
                p_n = prod_name[i]
                p_q = prod_qty[i]
                p_p = prod_price[i]
                # this is checking the variable, if variable is null so fill the varable value in database
                if p_n != "" and p_q != "" and p_p != "":
                    prod_tab = Products(product_name=p_n, product_qty=p_q, product_price=p_p, customer_id=custo_id)
                    prod_tab.save()
                i=i+1

Ответ 11

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

 def viewfunc(request):
     ...
     to_save = [];
     for item in items:
         entry = Entry(a1=item.a1, a2=item.a2)
         to_save.append(entry);
     map(lambda x: x.save(), to_save);