使用pyodbc进行批量插入+使用NoneNan时SQL服务器速度慢+解决方法

问题描述 投票:2回答:1

问题是试图将数据上传到SQL Server,得到的速度是每秒122行(17列)。我决定把问题和解决方法一起贴在这里,希望有人知道确切的答案。

我找到的最相关的帖子是,但问题有很大的不同,仍然没有答案。pyodbc - 非常慢的批量插入速度

这是一个简单的场景,我试图用Python将一个350K行的CSV上传到一个空白的SQL Server表中。在尝试了一个最流行的方法,即以pandas DataFrame的形式读取,创建一个sql_alchemy引擎,fast_executemany=True,然后使用to_sql()方法存储到数据库中。我得到了122行第二,这是不可接受的。

正如在其他线程中提到的,这种情况在PostgreSQL或Oracle中不会发生,我可以补充说,在MariaDB中也不会发生。所以我尝试了另一种方法,使用pyodbc cursor.executemany(),看看是否在pandas或sql_alchemy中出现了bug。同样的速度。

下一步是生成合成数据来复制问题提交bug......让我惊讶的是,生成的数据每秒约8000条记录。WTF?数据使用了与CSV中相同的数据类型(很明显)。

在尝试了几个星期的不同事情之后,我决定研究一下pydobc本身。在 pyodbc 的 github 开发网站上,我发现了一个有趣的信息。https:/github.comkleehammerpyodbcwikiBinding-Parameters。特别是在 编写NULL 并在 解决办法和变通办法 的部分。

的确,CSV第一行的17个字段中,有3个字段被我手动在Pandas中或None中转换为 "Nan"。令我惊讶的是,将这些NoneNanNULL替换为有效值后,在 仅限第一行,把速度提升到了7-8千条记录。请注意,我没有在后面的行文中更改任何NoneNan,只在第一行中更改。

有人明白为什么会发生这种情况吗?有没有比换成把NoneNan替换成有效值更优雅的解决方法?

更新: 在Github页面上似乎有几个相关的问题,都指向同一个问题。供参考。https:/github.comkleehammerpyodbcissues213。. 这个线程比较老了,是2017年的,但似乎在如何处理NoneNan的问题仍然存在。

python sql-server pyodbc
1个回答
1
投票

pyodbc至少到4.0.30版本,在与微软SQL Server对话时有一个bug。总的来说,SQL Server对不同的字段类型使用不同类型的NULL,pyodbc不能仅仅从 "None "来推断使用哪个NULL。为了克服这个限制,pyodbc实现了两种方法。

  • 允许使用.setinputsizes()方法将类型和大小传递给游标,或者;
  • 根据找到的第一个非None值来绑定类型。

默认情况下,当在第一行找到一个None时,参数被绑定为BINARY。每当发现同一字段的不同类型时,它都会重新检测并尝试重新绑定,但在第一次绑定之后的每一行都会这样做,导致性能下降。

使用.setinputsizes()方法将字段的类型传递给pyodbc.cursor应该可以完全避免这个问题,但现在当它在第一行发现'None'时,.setinputsizes()会被忽略。

pyodbc团队已经意识到这个问题,并将在未来的版本中进行修复。更多关于这个错误的信息 https:/github.comkleehammerpyodbcissues741。

目前,唯一有效的变通方法是创建一个虚拟记录作为第一行(在插入完成后删除),并为类型提供一个代表性的值,这样pyodbc就可以正确绑定正确的类型。

这个问题影响了所有使用pyodbc的包,包括SQL Alchemy,也间接影响了pandas。

© www.soinside.com 2019 - 2024. All rights reserved.