关于python:比executemany更快速的解决方案是在pyodbc中一次插入多行

Faster solution than executemany to insert multiple rows at once in pyodbc

我想用一个插入语句插入多行。

我尝试过

1
2
3
4
params = ((1, 2), (3,4), (5,6))
sql = 'insert into tablename (column_name1, column_name2) values (?, ?)'
cursor.fast_executemany = True
cursor.executemany(sql, params)

但这是在后台运行execute方法的参数上的简单循环。

我还尝试创建更长的insert语句,使其类似于INSERT INTO表名(col1,col2)VALUES(?,?),(?,?)...(?,?)。

1
2
3
4
5
6
def flat_map_list_of_tuples(list_of_tuples):
    return [element for tupl in list_of_tuples for element in tupl])

args_str = ', '.join('(?,?)' for x in params)
sql = 'insert into tablename (column_name1, column_name2) values'
db.cursor.execute(sql_template + args_str, flat_map_list_of_tuples(params))

有效,插入时间从10.9s减少到6.1。

此解决方案正确吗?它有一些漏洞吗?


Is this solution correct?

您建议的解决方案是构建表值构造函数(TVC),这不是不正确的,但实际上不是必需的。具有fast_executemany=True和Microsoft SQL Server的ODBC驱动程序17的pyodbc的速度与您按照本答案中所述使用BULK INSERTbcp的速度差不多。

Does it have some vulnerabilities?

由于您正在为参数化查询构建TVC,因此可以防止SQL注入漏洞,但是仍需考虑一些实现注意事项:

  • TVC一次最多可以插入1000行。

  • pyodbc通过调用系统存储过程来执行SQL语句,并且SQL Server中的存储过程最多可以接受2100个参数,因此TVC可以插入的行数也限制为(number_of_rows * number_of_columns <2100)。

  • 换句话说,您的TVC方法将被限制为1000行或更少的"块大小"。实际计算在此答案中描述。