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

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

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

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

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

Без коммиттератора коммитов (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

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

Ответы [ 9 ]

115 голосов
/ 16 июля 2009

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

из документации django по атомарным :

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()
11 голосов
/ 01 ноября 2011

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

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

3 голосов
/ 16 июля 2009

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

3 голосов
/ 16 июля 2009

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

2 голосов
/ 30 декабря 2013

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

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

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

2 голосов
/ 05 февраля 2011

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

Thomas

0 голосов
/ 02 мая 2019
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')
0 голосов
/ 02 мая 2019
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
0 голосов
/ 16 июля 2009

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

insert into A select from B;

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

...