您可以对代码进行一些更改。首先,您真的应该只创建一次 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 Prepared Statements 并一一执行每个插入。
使用 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 连接器/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 Prepared Statement。所以这很好。