use*_*354 5 python sql-server pyodbc
问题是试图将数据上传到 SQL Server 并获得每秒 122 行(17 列)的速度。我决定在此处发布问题以及解决方法,希望有人知道最终答案。
我发现的最相关的线程是但问题显着不同并且仍然没有答案: pyodbc - 非常慢的批量插入速度
这是一个简单的场景,我尝试使用 Python 将 350K 行的 CSV 上传到空白的 SQL Server 表中。在尝试了一种最流行的方法后,即将其作为pandas DataFrame 读取,创建一个带有fast_executemany=True 的sql_alchemy 引擎并使用to_sql() 方法存储到数据库中。我得到了 122 行/秒,这是不可接受的。
正如其他线程中提到的,这不会发生在 PostgreSQL 或 Oracle 中,我可以补充说,它也不会发生在 MariaDB 中。所以我尝试了一种不同的方法,使用 pyodbc cursor.executemany() 来查看 pandas 或 sql_alchemy 中是否存在错误。速度一样。
下一步是生成合成数据来复制问题以提交错误……令我惊讶的是,生成的数据大约为 8000 条记录/秒。跆拳道?数据使用的数据类型(显然)与 CSV 中的数据类型相同。
经过数周的尝试,我决定研究 pydobc 本身。在 pyodbc github 开发站点中,我在https://github.com/mkleehammer/pyodbc/wiki/Binding-Parameters 中发现了一条有趣的信息,特别是在Writing NULL和Solutions and Workarounds部分。
事实上,CSV 第一行的 17 个字段中有 3 个被我手动转换为 Pandas 中的“Nan”或 None 。令我惊讶的是,将这些 None/Nan/NULL 替换为FIRST LINE ONLY上的有效值,将速度提高到 7-8000 条记录/秒。请注意,我没有更改后续行中的任何 None/Nan,仅更改了第一行。
有谁明白为什么会发生这种情况?有没有比切换到将 None/Nan 替换为有效值更优雅的解决方法?
更新:Github 页面上似乎有几个相关问题,并且都指向同一问题。供参考:https : //github.com/mkleehammer/pyodbc/issues/213。该线程相对较旧,从 2017 年开始,但似乎如何处理 None/Nan 的问题仍然存在。
与 Microsoft SQL Server 交互时,pyodbc 至少在 4.0.30 版本中存在错误。总之,SQL Server 对不同的字段类型使用不同类型的 NULL,并且 pyodbc 无法仅从“None”推断出要使用哪个 NULL。为了克服这个限制,pyodbc 实现了两种方法:
默认情况下,当在第一行找到 None 时,该参数将绑定到 BINARY。每次为同一字段找到不同的类型时,它都会重新检测并尝试重新绑定,但会对第一次绑定后的每个后续行执行此操作,从而导致性能下降。
使用方法 .setinputsizes() 将字段的类型传递给 pyodbc.cursor 应该可以完全避免这个问题,但现在当 .setinputsizes() 在第一行中找到“None”时,它会被忽略。
pyodbc 团队已意识到该问题,并将在未来版本中进行修复。有关此错误的更多信息,请访问https://github.com/mkleehammer/pyodbc/issues/741
目前,唯一有效的解决方法是创建一个虚拟记录作为第一行(插入完成后将被删除)并具有类型的代表值,以便 pyodbc 可以正确绑定正确的类型。
此问题影响所有使用 pyodbc 的包,包括 SQL Alchemy 以及间接的 pandas。
| 归档时间: |
|
| 查看次数: |
619 次 |
| 最近记录: |