在python
中,我有一个从一个数据库中选择数据的过程(Redshift
通过psycopg2
),然后将该数据插入SQL Server
(通过pyodbc
})。我选择进行读/写而不是读/平文件/加载,因为行数大约是每天100,000。似乎更容易简单地连接和插入。但是 - 插入过程很慢,需要几分钟。
有没有更好的方法使用Pyodbc将数据插入SQL Server?
select_cursor.execute(output_query)
done = False
rowcount = 0
while not done:
rows = select_cursor.fetchmany(10000)
insert_list = []
if rows == []:
done = True
break
for row in rows:
rowcount += 1
insert_params = (
row[0],
row[1],
row[2]
)
insert_list.append(insert_params)
insert_cnxn = pyodbc.connect('''Connection Information''')
insert_cursor = insert_cnxn.cursor()
insert_cursor.executemany("""
INSERT INTO Destination (AccountNumber, OrderDate, Value)
VALUES (?, ?, ?)
""", insert_list)
insert_cursor.commit()
insert_cursor.close()
insert_cnxn.close()
select_cursor.close()
select_cnxn.close()
答案 0 :(得分:4)
更新: pyodbc 4.0.19添加了Cursor#fast_executemany
选项,可以避免下面描述的行为,从而大大提高性能。有关详细信息,请参阅this answer。
您的代码确实遵循了正确的形式(除了在其他答案中提到的一些小调整),但请注意,当pyodbc执行.executemany
实际执行的操作时,请提交单独的sp_prepexec
每一行。也就是说,对于代码
sql = "INSERT INTO #Temp (id, txtcol) VALUES (?, ?)"
params = [(1, 'foo'), (2, 'bar'), (3, 'baz')]
crsr.executemany(sql, params)
SQL Server实际执行以下操作(由SQL事件探查器确认)
exec sp_prepexec @p1 output,N'@P1 bigint,@P2 nvarchar(3)',N'INSERT INTO #Temp (id, txtcol) VALUES (@P1, @P2)',1,N'foo'
exec sp_prepexec @p1 output,N'@P1 bigint,@P2 nvarchar(3)',N'INSERT INTO #Temp (id, txtcol) VALUES (@P1, @P2)',2,N'bar'
exec sp_prepexec @p1 output,N'@P1 bigint,@P2 nvarchar(3)',N'INSERT INTO #Temp (id, txtcol) VALUES (@P1, @P2)',3,N'baz'
因此,对于.executemany
"批次"你将是10,000行
INSERT INTO ...
)10,000次。 可能让pyodbc发送初始sp_prepare
然后执行.executemany
调用sp_execute
,但.executemany
的性质是您仍然会执行10,000 sp_prepexec
次来电,只执行sp_execute
而不是INSERT INTO ...
。如果SQL语句很长很复杂,那么这可以提高性能,但对于像你问题中的例子这样的简短版本,它可能不会产生那么大的差异。
还可以创造性地构建"表值构造函数"如this answer所示,但请注意,它仅作为"计划B"当本机批量插入机制不可行时。
答案 1 :(得分:0)
您已经在使用 [在阅读其他答案后被淘汰。] executemany()
了。
如果您在while循环之外移动connect()
和cursor()
insert_cnxn
和insert_cursor
来调用它,则应加快(非常小)位。 (当然,如果你这样做,你也应该在循环之外移动2个相应的close()
调用。)除了不必每次都重新建立连接,重新使用游标将阻止每次都重新编译SQL。
但是,你可能不会因此而看到一个巨大的加速,因为你可能只需要通过该循环进行约10次传递(假设你说每天大约100,000次,你的循环组合在一起)一次10,000个。)
您可能会关注的另一件事是,是否有任何"幕后花絮"正在对您的OrderDate
参数进行转换。您可以转到SQL Server Management Studio并查看查询的执行计划。 (通过右键单击服务器节点并选择" Activity Monitor"在"最近的昂贵查询"列表中查找插入查询;右键单击插入查询并查看其执行计划。)