加速从数据库获得的一些数据运行大型进程

时间:2014-08-04 09:23:51

标签: python mysql django

所以我在一个项目中工作,我必须读取一个包含1000万条记录的大型数据库(对我来说很大)。我无法真正过滤它们,因为我必须全部和个别地对待它们。对于每个记录,我必须应用一个公式,然后根据记录的某些条件将此结果写入多个文件。

我已经实施了一些算法并完成整个处理需要大约2-3天。这是一个问题,因为我正在尝试优化已经花费这段时间的流程。 1天是可以接受的。

到目前为止,我已经尝试了数据库上的索引,线程(记录过程而不是I / O操作)。我不能缩短时间。

我正在使用django,并且我无法衡量由于其懒惰行为而真正开始处理数据需要多少。我还想知道我是否可以在收到数据后立即开始处理数据,而不必等待所有数据加载到内存中,然后才能实际处理它。这也可能是我对python上编写操作的理解。最后可能是我需要一台更好的机器(我怀疑它,我有4核和4GB RAM,它应该能够提供更好的速度)

有什么想法吗?我真的很感激反馈。 :)

编辑:代码

说明:

我所谈到的记录是客户的ids(护照),条件是公司的不同终端(国家)之间是否有协议。这个过程是一个散列。

第一种策略试图对待整个数据库......我们在开始时已经准备好处理算法的条件部分(国家之间的协议)。然后通过属于或不属于集合进行大量验证。

由于我一直在努力改进它,我试图在第二个策略的部分内容中解决问题,按部分处理查询(获取属于某个国家/地区的记录并写入文件)那些与他们达成协议的人)

没有描述线程策略,因为它是针对单个国家设计的,与没有线程相比,我得到了糟糕的结果。老实说,我必须有直觉才能成为内存和sql。

def create_all_files(strategy=0):
    if strategy == 0:
        set_countries_agreements = set()
        file_countries = open(os.path.join(PROJECT_ROOT, 'list_countries'))
        set_countries_temp = set(line.strip() for line in file_countries)
        file_countries.close()
        set_countries = sorted_nicely(set_countries_temp)

        for each_country in set_countries:
            set_agreements = frozenset(get_agreements(each_country))
            set_countries_agreements.add(set_agreements)

        print("All agreements obtained")

        set_passports = Passport.objects.all()

        print("All passports obtained")


        for each_passport in set_passports:
            for each_agreement in set_countries_agreements:
                for each_country in each_agreement:
                    if each_passport.nationality == each_country:
                        with open(os.path.join(PROJECT_ROOT, 'generated_indexes/%s' % iter(each_agreement).next()), "a") as f:
                            f.write(generate_hash(each_passport.nationality + "<" + each_passport.id_passport, each_country) + "\n")
                    print(".")
                print("_")
            print("-")
        print("~")

    if strategy == 1:

        file_countries = open(os.path.join(PROJECT_ROOT, 'list_countries'))
        set_countries_temp = set(line.strip() for line in file_countries)
        file_countries.close()
        set_countries = sorted_nicely(set_countries_temp)

        while len(set_countries)!= 0:
            country = set_countries.pop()
            list_countries = get_agreements(country)
            list_passports = Passport.objects.filter(nationality=country)
            for each_passport in list_passports:
                for each_country in list_countries:
                    with open(os.path.join(PROJECT_ROOT, 'generated_indexes/%s' % each_country), "a") as f:
                        f.write(generate_hash(each_passport.nationality + "<" + each_passport.id_passport, each_country) + "\n")
                        print("r")
                print("c")
            print("p")
        print("P")

2 个答案:

答案 0 :(得分:1)

在您的问题中,您正在描述ETL进程。 我建议您使用ETL工具

提到一些python ETL工具,我可以谈论Pygrametl,由Christian Thomsen撰写,在我看来它运行得很好,而且它的性能令人印象深刻。测试并回归结果。

我不能在不提及MapReduce的情况下发布此答案。如果您计划通过节点分发任务,那么这种编程模型可以满足您的要求。

答案 1 :(得分:1)

看起来您为每个国家/地区添加了哈希值的文件,而不是打开和关闭这些文件的句柄1000万次以上,您应该打开每一个文件一次并在最后关闭它们。

countries = {}  # country -> file
with open(os.path.join(PROJECT_ROOT, 'list_countries')) as country_file:
    for line in country_file:
        country = line.strip()
        countries[country] = open(os.path.join(PROJECT_ROOT, 'generated_indexes/%s' % country), "a")

for country in countries:
    agreements = get_agreements(country)
    for postcode in Postcode.objects.filter(nationality=country):
        for agreement in agreements:
            countries[agreement].write(generate_hash(passport.nationality + "<" + passport.id_passport, country_agreement) + "\n")

for country, file in countries.items():
    file.close()

我不知道Postcode个对象Postcode.objects.filter(nationality=country)的列表会返回多大,如果它很大并且内存是个问题,你将不得不开始考虑使用{分块/分页查询{3}}

您正在使用国家/地区列表及其协议的集合,如果因为您的文件包含国家/地区列表不保证是唯一的,那么当您尝试打开同一文件的另一个句柄时,字典解决方案可能会出错。通过添加一个简单的检查以查看该国家/地区是否已成为countries

的成员,可以避免这种情况