所以我在一个项目中工作,我必须读取一个包含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")
答案 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