【问题标题】:What is an efficient way of inserting thousands of records into an SQLite table using Django?使用 Django 将数千条记录插入 SQLite 表的有效方法是什么?
【发布时间】:2010-11-11 06:55:48
【问题描述】:

我必须使用 Django 的 ORM 将 8000 多条记录插入 SQLite 数据库。此操作需要作为 cronjob 大约每分钟运行一次。
目前我正在使用 for 循环遍历所有项目,然后将它们一一插入。
示例:

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

这样做的有效方法是什么?

编辑:两种插入方式的小对比。

没有 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

注意:除了插入数据库之外,test 脚本还执行一些其他操作(下载 ZIP 文件,从 ZIP 存档中提取 XML 文件,解析 XML文件),因此执行所需的时间并不一定代表插入记录所需的时间。

【问题讨论】:

    标签: python sql django sqlite insert


    【解决方案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()
    

    这只会提交一次,而不是在每次 save() 时提交。

    在 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_successcommit_manually

    来自 django documentation on 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()
    

    【讨论】:

    • 这会将它们全部实例化为模型,并运行数千个单独的插入。我总是不得不使用 SQL 并为这种类型的卷进行手动批量插入; Django 不是为它而构建的。但是,是的,如果您这样做,您肯定想要单笔交易。
    • 我没有 .net 经验,但从一般数据库的角度来看,关闭 AUTOCOMMIT 并在 BEGIN/END TRANSACTION 语句之间封装 INSERT 语句将比使用 AUTOCOMMIT 和单独运行 INSERTS 更快。请注意,这些命令及其使用方式可能会根据您使用的数据库而改变。如果您想要 .net 或 .net 框架特定的答案,请继续并开始一个新问题。
    • 既然 Django 1.4 已经发布,使用docs.djangoproject.com/en/dev/ref/models/querysets/… 更有意义。另一种快速的替代方法是手动创建批处理 SQL 插入。这里的提示(在一个事务中提交)不会像在一个插入中发送一样快。
    • 从 1.9 开始,bulk_create 运行良好。请注意,您需要将创建分解成批次,为 SQLite 添加的属性总数不超过 999 个。
    • 值得注意的是transaction.atomic 不会使代码运行得更快。否则,很好的总结,谢谢。
    【解决方案2】:

    【讨论】:

    • 它的工作方式与保存的工作方式相同吗?例如保存或更新每个对象?
    【解决方案3】:

    看看this。它仅适用于开箱即用的 MySQL,但有一些关于如何处理其他数据库的指针。

    【讨论】:

      【解决方案4】:

      批量加载项目可能会更好 - 准备一个文件并使用批量加载工具。这将比 8000 个单独的插入更有效。

      【讨论】:

        【解决方案5】:

        要回答特别是关于 SQLite 的问题,如所问,虽然我刚刚确认 bulk_create 确实提供了巨大的加速,但 SQLite 有一个限制:“默认是在一批中创建所有对象,除了SQLite 默认情况下,每个查询最多使用 999 个变量。"

        引用的内容来自文档 --- A-IV 提供了一个链接。

        我要补充的是,alpar 的this djangosnippets 条目似乎也对我有用。它是一个小包装器,可将您要处理的大批量拆分为小批量,管理 999 个变量的限制。

        【讨论】:

        • 对于 Django ≥1.5,Django sn-p 应该是不必要的,对吧?从 Django 1.5 开始,您可以使用一个 batch_size 参数:“batch_size 参数控制在单个查询中创建多少个对象。默认是在一个批次中创建所有对象,但 SQLite 除外,其中默认值是这样的每个查询最多使用 999 个变量。batch_size 参数是在 1.5 版中添加的。"
        【解决方案6】:

        您应该查看DSE。我编写 DSE 来解决这类问题(大量插入或更新)。使用 django orm 是一条死路,您必须使用纯 SQL 来完成,而 DSE 会为您处理大部分工作。

        托马斯

        【讨论】:

        • 另一件事;如果您决定使用普通 SQL,并且您插入的 SQL 每次都具有相同的字段,请尝试使用 cursor.executemany(SQL, [list of entries to insert])。比为每个条目运行插入要快得多。
        【解决方案7】:
        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')
        

        【讨论】:

        • 这段代码运行正常。我被检查了我的水平。如果您身边发生任何错误,请再次检查代码并理解此代码的含义,然后再试一次。并且任何人都知道在数据库中一次插入多个数据的更好,更简单的方法,请与我们分享。谢谢
        • 请在您的答案中直接包含澄清、进一步解释等,而不是使用comments。评论应用于询问更多信息或提出改进建议。
        【解决方案8】:
        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
        

        【讨论】:

        • 不鼓励像您这样的纯代码答案。
        【解决方案9】:

        我建议使用纯 SQL(不是 ORM),您可以通过一次插入来插入多行:

        insert into A select from B;
        

        只要结果与表 A 中的列匹配并且没有约束冲突,您的 sql 的 select from B 部分就可以像您希望的那样复杂。

        【讨论】:

          猜你喜欢
          • 2010-10-25
          • 1970-01-01
          • 2015-04-04
          • 2012-10-19
          • 1970-01-01
          • 1970-01-01
          • 2016-05-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多