用.executemany()加速MySQL INSERT操作

时间:2014-06-03 16:55:40

标签: python mysql performance cursor oursql

如何在此处使用executemany来加快这一过程。

with dest_conn.cursor() as dcur:
    while True:
        rows = scur.fetchmany(size=25)
        if rows:
            place_holders = "(%s)" % ','.join("?"*len(rows[0]))
            place_holders_list = ', '.join([place_holders] * len(rows))
            insert_query = "INSERT IGNORE INTO `%s` VALUES %s" % (tname, place_holders_list)
            dcur.execute(insert_query, (val for row in rows for val in row))

        else:
            log("No more rows found to insert")
            break

此处dcur目标光标复制数据的位置和scur是我从

获取数据的源光标

即使我一次插入25行(我发现这个数字对我的数据库来说是最佳的)我正在创建一个准备好的语句并执行它们。 oursql手册说executemany的速度更快。它可以批量发送所有值。我如何在此处使用它而不是execute

1 个答案:

答案 0 :(得分:2)

您可以更改代码中的一些内容。首先,你真的应该只创建一次insert_query字符串。它永远不会在循环中改变。此外,您似乎有一些错误,例如'?' * nr没有返回序列,所以我也纠正了这些错误。

使用oursql

import oursql

# ...

place_holders = '(' + ','.join(['?'] * len(scur.description)) + ')'
insert_query = "INSERT IGNORE INTO `%s` VALUES %s" % (tname, place_holders)

with dest_conn.cursor() as dcur:
    while True:
        rows = scur.fetchmany(size=25)
        if not rows:
            log("No more rows found to insert")
            break

        dcur.executemany(insert_query, rows)

但是,我没有看到executemany()方法做了很多优化。它将始终使用MySQL Prepared Statements并逐个执行每个插入。

MySQL使用oursql执行的常规日志条目:

..
14 Prepare  SELECT * FROM t1
14 Execute  SELECT * FROM t1
15 Prepare  INSERT INTO `t1copy` VALUES (?)
15 Execute  INSERT INTO `t1copy` VALUES (1)
15 Execute  INSERT INTO `t1copy` VALUES (2)
15 Execute  INSERT INTO `t1copy` VALUES (3)
..

使用MySQL Connector / Python

如果你使用MySQL Connector / Python(注意,我是维护者),你会看到不同的查询进入MySQL服务器。这里是类似的代码,但是重新编写,因此它运行mysql.connector:

import mysql.connector

# ...

place_holders = ','.join(['%s'] * len(scur.description))
place_holders_list = ', '.join([place_holders] * len(scur.description))
insert_query = "INSERT INTO `{0}` VALUES ({1})".format(tname, place_holders_list)

dcur = dest_conn.cursor()
while True:
    rows = scur.fetchmany(size=25)
    if not rows:
        log("No more rows found to insert")
        break

    dcur.executemany(insert_query, rows)
    dest_conn.commit()

MySQL使用mysql.connector执行的常规日志条目:

..
18 Query    SELECT * FROM t1
19 Query    INSERT INTO `t1copy` VALUES (1),(2),(3),(4),(5),(6),(1),(2),(3),(4),(5),(6)
19 Query    COMMIT

什么是更快的必须进行基准测试。 oursql正在使用MySQL C库; MySQL Connector / Python是纯Python。因此,制作优化插入的魔力也是纯Python字符串解析,因此您必须检查它。

结论

oursql没有优化INSERT语句本身。相反,executemany()只创建一次MySQL Prepared Statement。这很好。