python - 使用 .executemany() 加速 MySQL INSERT 操作

标签 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

最佳答案

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

使用我们的sql

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 准备语句并逐条执行每个插入。

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

..
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 连接器/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.connector 执行的 MySQL 常规日志条目:

..
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 连接器/Python 是纯 Python。因此,进行优化插入的魔法也是纯 Python 字符串解析,因此您必须检查它。

结论

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

关于python - 使用 .executemany() 加速 MySQL INSERT 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24020795/

相关文章:

python - numpy:获取网格中的正方形坐标

mysql - 如何从 MySQL 中的 DATETIME 中的毫秒中删除尾随零

python - 查找区间索引的有效方法

Python更改用startfile打开的exe文件的工作目录

php - 如何列出 DATETIME 数据的年龄明智结果

mysql - 从 minikube 访问在本地主机上运行的 mysql

mysql - 在 SQL 中,什么是更快的 : LIMIT . .. OFFSET 或范围查询?

sql-server - 我可以停止调用 sp_reset_connection 以提高性能吗?

c# - 为什么数组项分配会降低 C# 程序的性能?

python - 如何使urlib在python中返回数组-解析对elasticsearch的调用结果?