使用python(Django)优化填充数据库的代码

使用python(Django)优化填充数据库的代码,python,django,performance,Python,Django,Performance,我正在尝试使用Django填充一个SQLite数据库,其中包含来自一个包含600万条记录的文件的数据。然而,我编写的代码给了我很多时间问题,即使有50000条记录 这是我试图填充数据库的代码: import os def populate(): with open("filename") as f: for line in f: col = line.strip().split("|") duns=col[1]

我正在尝试使用Django填充一个SQLite数据库,其中包含来自一个包含600万条记录的文件的数据。然而,我编写的代码给了我很多时间问题,即使有50000条记录

这是我试图填充数据库的代码:

import os

def populate():   
    with open("filename") as f:
        for line in f:
            col = line.strip().split("|")
            duns=col[1]
            name=col[8]
            job=col[12]        

            dun_add = add_c_duns(duns)   
            add_contact(c_duns = dun_add, fn=name, job=job)

def add_contact(c_duns, fn, job):
    c = Contact.objects.get_or_create(duns=c_duns, fullName=fn, title=job)
    return c

def add_c_duns(duns):
    cd = Contact_DUNS.objects.get_or_create(duns=duns)[0]
    return cd  

if __name__ == '__main__':
    print "Populating Contact db...."
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
    from web.models import Contact, Contact_DUNS
    populate()
    print "Done!!"

代码运行良好,因为我已经用虚拟记录测试了它,它给出了期望的结果。我想知道是否有一种方法可以降低代码的执行时间。谢谢

我没有足够的声誉来评论,但这里有一个推测性的答案

基本上,通过django的ORM实现这一点的唯一方法是使用
bulk\u create
。所以首先要考虑的是使用<代码> GETIORORIGORION/CODE >。如果您的数据库中有可能在输入文件中有重复记录的现有记录,那么您唯一的选择就是自己编写SQL。如果使用它来避免输入文件中出现重复的行,请对其进行预处理以删除重复的行

因此,如果您可以不使用
get\u或\u create
的get部分,那么您可以遵循以下策略:

  • 检查输入文件的每一行,并为每个条目实例化一个Contact_DUNS实例(不实际创建行,只需编写
    Contact_DUNS(DUNS=DUNS)
    ),并将所有实例保存到一个数组中。将数组传递到
    bulk\u create
    以实际创建行

  • 生成具有
    value\u list
    的DUNS id对列表,并将其转换为以DUNS编号为键、行id为值的
    dict

  • 对Contact实例重复步骤1。在创建每个实例之前,使用DUNS编号从步骤2的字典中获取联系人id。用户可以用以下方式实例化每个联系人:
    联系人(duns\u id=c\u duns\u id,fullName=fn,title=job)
    。同样,收集联系人实例后,只需将它们传递到
    bulk\u create
    即可创建行

  • 这将从根本上提高性能,因为您将不再对每个输入行执行查询。但是,正如我上面所说的,只有当您能够确定数据库或输入文件中没有重复项时,这才能起作用

    编辑以下是代码:

    import os
    
    def populate_duns():
        # Will only work if there are no DUNS duplicates
        # (both in the DB and within the file)
        duns_instances = []   
        with open("filename") as f:
            for line in f:
                duns = line.strip().split("|")[1]        
                duns_instances.append(Contact_DUNS(duns=duns))
    
        # Run a single INSERT query for all DUNS instances
        # (actually it will be run in batches run but it's still quite fast)
        Contact_DUNS.objects.bulk_create(duns_instances)
    
    def get_duns_dict():
        # This is basically a SELECT query for these two fields
        duns_id_pairs = Contact_DUNS.objects.values_list('duns', 'id')
        return dict(duns_id_pairs)
    
    def populate_contacts():
        # Repeat the same process for Contacts
        contact_instances = []
        duns_dict = get_duns_dict()
    
        with open("filename") as f:
            for line in f:  
                col = line.strip().split("|")
                duns = col[1]
                name = col[8]
                job = col[12]
    
                ci = Contact(duns_id=duns_dict[duns],
                             fullName=name,
                             title=job)
                contact_instances.append(ci)
    
        # Again, run only a single INSERT query
        Contact.objects.bulk_create(contact_instances)
    
    if __name__ == '__main__':
        print "Populating Contact db...."
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
        from web.models import Contact, Contact_DUNS
        populate_duns()
        populate_contacts()
        print "Done!!"
    

    通过Python导入6000000是相当多的。如果Python不是一个硬需求,那么可以编写一个SQLite脚本,直接使用SQL语句创建表。更快的方法是使用预处理文件,并输出与两个表对应的两个CSV文件


    我以前使用sqlite3 CSV导入器导入20000000条记录,只需几分钟。

    CSV导入

    首先,对于sqllite来说,600万条记录是相当多的,更糟糕的是sqlite和直接导入CSV数据

    对于CSV文件应该是什么样子没有标准,而且 SQLite shell甚至不尝试处理 解释CSV文件。如果需要导入复杂的CSV文件和 SQLite shell无法处理它,您可能需要尝试其他方法 前端,如SQLite数据库浏览器

    另一方面,Mysql和Postgresql更能处理CSV数据,Mysql和Postgresql都是在很短的时间内导入大量数据的无痛方法

    Sqlite的适用性。

    您正在使用django=>您正在构建一个web应用=>多个用户将访问数据库。这是从手册上讲的

    SQLite支持无限数量的同时读卡器,但是 在任何时刻都只允许一个编写器。对许多人来说 在某些情况下,这不是问题。作家排队。每次申请 它的数据库是否能快速工作并继续运行,并且没有一个锁会持续一段时间 超过几十毫秒。但也有一些应用 这需要更多的并发性,这些应用程序可能需要 一个不同的解决方案

    甚至您的读取操作也可能相当慢,因为sqlite数据库只是一个文件。因此,有了这么多的数据,将涉及到大量的seek操作。使用适当的客户机-服务器数据库,数据不能尽可能分布在多个文件甚至磁盘上

    好消息是,使用Django,您通常可以通过更改settings.py从Sqlite切换到Mysql再切换到Postgresql。不需要进行其他更改。(事实并非总是相反)


    因此,我敦促你在深入研究之前考虑切换到MySQL或PiggRESL。它将帮助您解决当前的问题,也有助于避免您迟早会遇到的问题。

    ORM很少擅长批量操作(在任何语言中)。他们需要在内存中创建对象,跟踪状态等。。。他们也倾向于低效率地使用连接,并且不优化/批处理多个操作。更糟糕的是,您要求ORM在选择操作(插入/更新)之前检查对象是否存在,这会增加每条记录的开销。根据您使用的数据库引擎,查看相应的批量导入工具或(至少)生成原始SQL语句。我目前正在尝试批量创建()和原始(),仍在编写代码,如果您能帮助我批量创建,我将不胜感激!!!