目前我有一个日志解析器正在读取515MB的纯文本文件(过去四年中每天一个文件)。我的代码目前是这样的:http://gist.github.com/12978。我使用了Psyco(如代码所示),并编译并使用编译版本。它每0.3秒处理约100行。这台机器是标准的15英寸MacBook Pro(2.4ghz C2D,2GB RAM)。
这个速度是否可以更快,还是这是语言/数据库的限制?
目前我有一个日志解析器正在读取515MB的纯文本文件(过去四年中每天一个文件)。我的代码目前是这样的:http://gist.github.com/12978。我使用了Psyco(如代码所示),并编译并使用编译版本。它每0.3秒处理约100行。这台机器是标准的15英寸MacBook Pro(2.4ghz C2D,2GB RAM)。
这个速度是否可以更快,还是这是语言/数据库的限制?
不要浪费时间进行性能分析。时间总是花在数据库操作上。尽量少做,只做最少量的插入。
三个建议:
一、不要反复选择日期、主机名和人员维度来确认数据。将所有数据一次性获取到Python字典中,在内存中使用它。不要进行重复的单例选择。使用Python。
二、不要更新。
具体来说,不要这样做。这段代码有两个问题。
cursor.execute("UPDATE people SET chats_count = chats_count + 1 WHERE id = '%s'" % person_id)
应该用一个简单的SELECT COUNT(*) FROM ...来替换它。永远不要更新以增加计数。只需使用SELECT语句计算存在的行数。[如果您无法使用简单的SELECT COUNT或SELECT COUNT(DISTINCT)实现此目的,则缺少某些数据--您的数据模型应始终提供正确的完整计数。永远不要更新。]
另外,永远不要使用字符串替换构建SQL。完全是愚蠢的。
如果由于某种原因SELECT COUNT(*)不够快(在执行任何糟糕操作之前,请先进行基准测试),可以将计数结果缓存到另一个表中。在所有加载之后执行SELECT COUNT(*) FROM whatever GROUP BY whatever,并将其插入计数表中。永远不要更新。
三,始终使用绑定变量。
cursor.execute( "INSERT INTO ... VALUES( %(x)s, %(y)s, %(z)s )", {'x':person_id, 'y':time_to_string(time), 'z':channel,} )
SQL语句永远不会改变。绑定的值可能会变,但SQL语句本身不会改变。这种方式速度要快得多。永远不要动态构建SQL语句,绝对不要。
在for循环中,您正在重复插入“chats”表,因此您只需要一个带有绑定变量的单个SQL语句,以使用不同的值执行。 因此,您可以将此放在for循环之前:
insert_statement="""
INSERT INTO chats(person_id, message_type, created_at, channel)
VALUES(:person_id,:message_type,:created_at,:channel)
"""
然后,替换每个执行的SQL语句,将其替换为以下内容:
cursor.execute(insert_statement, person_id='person',message_type='msg',created_at=some_date, channel=3)
除了@Mark Roddy提出的许多好建议之外,还要做以下操作:
readlines
,可以迭代文件对象executemany
而不是execute
:尝试进行批量插入而不是单个插入,这通常更快,因为开销较小。它还减少了提交的次数str.rstrip
将完全可以代替使用正则表达式去掉换行符批处理插入将在暂时使用更多内存,但当您不将整个文件读入内存时,这应该是可以接受的。