我需要遍历一个非常大的文本文件,大小为几千兆字节(确切地说是一个区域文件)。我需要为区域文件中的每个条目运行一些查询,然后将结果存储在可搜索的数据库中。
目前我选择的武器,主要是因为我了解它们,是Python和MySQL。但是,我不确定这样处理这种大小的文件会有多好。
在此领域有经验的人是否有任何关于打开和循环文件而不会使系统超载的最佳方法的建议?一旦打开文件(线程化?)并存储处理过的数据,如何最有效地处理文件?
答案 0 :(得分:5)
在MySQL中存储大量数据时不应该有任何问题,尽管您可能无法将整个数据库存储在内存中,因此需要一些IO性能问题。与往常一样,在运行查询之前,请确保您拥有适当的索引。
最重要的是不要尝试将整个文件加载到内存中。循环遍历文件,不要尝试使用像readlines那样一次加载整个文件的方法。
确保批量处理请求。一次加载几千行,并在一个大的SQL请求中发送它们。
这种方法应该有效:
def push_batch(batch):
# Send a big INSERT request to MySQL
current_batch = []
with open('filename') as f:
for line in f:
batch.append(line)
if len(current_batch) > 1000:
push_batch(current_batch)
current_batch = []
push_batch(current_batch)
区域文件通常是格式化的,考虑一下你是否可以使用LOAD DATA INFILE。您还可以考虑创建一个命名管道,从python中将部分格式化的数据推送到它,并使用LOAD DATA INFILE将其读入MySQL。
MySQL在optimizing inserts上有一些很棒的提示,其中一些亮点是:
最快的处理将在MySQL中完成,因此请考虑在数据进入数据库之后是否能够完成所需的查询,而不是之前。如果您确实需要在Python中进行操作,则线程不会对您有所帮助。只有一个Python代码线程可以一次执行(GIL),所以除非您在C中花费大量时间或者使用外部资源进行接口,否则您只能在一个线程中运行反正。
最重要的优化问题是什么是速度,如果数据库是边界因素,那么就没有必要启动一堆线程来读取文件。真正知道的唯一方法是尝试并进行调整,直到它足够快到达你的目的。
答案 1 :(得分:0)
@Zack Bloom的答案非常好,我赞成它。只是几个想法:
正如他所展示的那样,只需使用with open(filename) as f:
/ for line in f
就可以了。 open()
返回一个迭代器,它一次从文件中为您提供一行。
如果您希望将每一行都插入数据库,请在循环中执行此操作。如果您只想要某些与某个正则表达式匹配的行,那很容易。
import re pat = re.compile(some_pattern) with open(filename) as f: for line in f: if not pat.search(line): continue # do the work to insert the line here
对于一个数千兆字节的文件,您很可能受到I / O限制。所以很可能没有理由担心多线程或其他什么。即使运行几个正则表达式,也可能比读取文件或更新数据库更快地处理数据。
就个人而言,我不是一个数据库人,我喜欢使用ORM。我做数据库工作的最后一个项目,我正在使用带有SQLite的Autumn。我发现ORM的默认设置是每次插入一次提交,并且插入一堆记录需要花费很长时间,因此我将Autumn扩展为允许您使用单个提交显式包含一堆插入;以这种方式更快很多。 (嗯,我应该扩展Autumn以使用Python with
语句,这样你就可以将一堆插入包装到with
块中,而Autumn会自动提交。)
无论如何,我的观点只是对数据库的东西,以错误的方式做事可能会很慢。如果您发现数据库插入是您的瓶颈,那么您可以采取一些措施来解决它,而Zack Bloom的答案包含了一些启发您的想法。