使用SQLAlchemy将记录更快地插入表中

时间:2010-05-21 12:12:53

标签: python sql mysql sqlite sqlalchemy

我正在使用SQLAlchemy和Python解析日志并将其插入MySQL或SQLite。现在我打开了与DB的连接,当我遍历每一行时,我在解析后插入它(这只是一个大表,现在对SQL不是很有经验)。然后我在循环完成时关闭连接。汇总代码为:

log_table = schema.Table('log_table', metadata,
                         schema.Column('id', types.Integer, primary_key=True),
                         schema.Column('time', types.DateTime),
                         schema.Column('ip', types.String(length=15))
....
engine = create_engine(...)
metadata.bind = engine
connection = engine.connect()
....
for line in file_to_parse:
    m = line_regex.match(line)
    if m:
        fields = m.groupdict()
        pythonified = pythoninfy_log(fields) #Turn them into ints, datatimes, etc
        if use_sql:
            ins = log_table.insert(values=pythonified)
            connection.execute(ins)
            parsed += 1

我的两个问题是:

  • 有没有办法在这个基本框架内加速插入?可能有一个插入队列和一些插入线程,某种批量插入等?
  • 当我使用MySQL时,大约120万条记录的插入时间为15分钟。使用SQLite,插入时间是一个多小时。数据库引擎之间的时间差异是否正确,或者它是否意味着我做错了什么?

3 个答案:

答案 0 :(得分:4)

你应该尝试的最重要的事情是围绕多个插入放置一个事务,因为它是将数据库提交到磁盘,这需要很长时间。您需要确定批处理级别,但原始的第一次尝试是将事务包装在整个批次中。

答案 1 :(得分:3)

在不知道表引擎(MyISAM?InnoDB?),架构和索引的情况下,很难对您在那里使用的两个数据库之间的细节进行评论。

然而,当像这样使用MySQL时,您可能会发现将数据写入临时文本文件然后use the LOAD DATA INFILE syntax将其全部加载到数据库中要快得多。看起来像you can call the execute method on your connection object来运行执行此操作所必需的SQL。

此外,如果您在逐行添加内容时设置为死,并且每次都要重新创建表,则可以验证程序中的关键约束,并仅在插入所有行后添加这些约束,从而保存数据库对每个插入进行约束检查的时间。

答案 2 :(得分:3)

我做了以下工作来实现一些批处理:

inserts = []
insert_every = 1000
for line in file_to_parse:
    m = line_regex.match(line)
    if m:
        fields = m.groupdict()
        if use_sql: #This uses Globals, Ick :-/
            inserts.append(pythonified)
            if (parsed % insert_every) == 0:
                connection.execute(log_table.insert(), inserts)
                inserts = []
            parsed += 1
if use_sql:
    if len(inserts) > 0:
        connection.execute(log_table.insert(), inserts)

这不使用事务,但是以非常懒惰的方式允许我使用较小的示例使用mysql后端将插入/解析阶段从~13秒转换为约~2秒。我将看到mysql和sqlite之间的区别在于使用完整示例进行此更改。

我找到了此here的基本信息。

<强>结果:
引擎:以分钟为单位的非分组插入时间:以分钟为单位的分组插入时间
源码:61:8
MySQL的:15:2.5

我没有在mysql和sqlite之间刷新我的缓存,这可能有源文本文件,但我认为这不会是一个相对显着的差异。