首页 > 解决方案 > SQLServer pyodbc 的 Python 驱动程序比 psycopg2 和带有插入的 mysql.connector 慢得多

问题描述

我们有一个用 Python 构建的应用程序,它必须在不同的数据库上运行,例如 SQLServer、MySQL 和 Postgres。当我们使用 pyodbc 库插入 SQL Server 时,这比使用 psycopg2 插入 Postgres 或使用 mysql.connector 插入 MySQL 要慢得多(20 倍!)。我有两个问题: 1. 造成这种性能差异的原因是什么?2. 我们能做什么(除了使用 Postgres/MySQL)?

标签: mysqlsql-serverpython-3.xpostgresqlpyodbc

解决方案


当 MySQL 连接器/Python 遇到executemany对 INSERT 语句的调用时,它会构造一个或多个多行 INSERT,从而减少到服务器的往返次数。例如,

crsr = cnxn.cursor()
sql = "INSERT INTO mytable (id) VALUES (%s)"
params = [(x,) for x in range(3)]
crsr.executemany(sql, params)

向 MySQL 服务器发送一条 INSERT 语句

INSERT INTO mytable (id) VALUES (0),(1),(2)

相比之下,pyodbc 的默认行为是发送单独的 INSERT 语句,因此

crsr = cnxn.cursor()
sql = "INSERT INTO mytable (id) VALUES (?)"
params = [(x,) for x in range(3)]
crsr.executemany(sql, params)

发送相当于

INSERT INTO mytable (id) VALUES (0)
INSERT INTO mytable (id) VALUES (1)
INSERT INTO mytable (id) VALUES (2)

需要三次往返服务器而不是一次。

幸运的是,当前版本的 pyodbc 支持通过 Cursor 对象的fast_executemany属性对 SQL Server 进行多行 INSERT ,因此

crsr = cnxn.cursor()
sql = "INSERT INTO mytable (id) VALUES (?)"
params = [(x,) for x in range(3)]
crsr.fast_executemany = True
crsr.executemany(sql, params)

产生与上面的 MySQL 连接器/Python 示例基本相同的结果。


推荐阅读