python - 使用 pyodbc 批量插入 + SQL Server 使用 None/Nan 很慢 + 解决方法

标签 python sql-server pyodbc

问题是尝试将数据上传到 SQL Server 并获得每秒 122 行(17 列)的速度。我决定在这里发布问题以及解决方法,希望有人知道明确的答案。

我发现的最相关的线程是,但问题有很大不同,仍然没有答案:
pyodbc - very slow bulk insert speed

这是一个简单的场景,我尝试使用 Python 将 350K 行的 CSV 上传到空白 SQL Server 表中。在尝试了一种最流行的方法后,即将其读取为 pandas DataFrame,创建一个 fast_executemany=True 的 sql_alchemy 引擎,并使用 to_sql() 方法存储到数据库中。我得到了 122 行/秒,这是 Not Acceptable 。

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

下一步是生成合成数据来复制问题以提交错误……令我惊讶的是,生成的数据大约是 8000 条记录/秒。怎么回事?数据使用的数据类型(显然)与 CSV 中的数据类型相同。

经过数周尝试不同的事情后,我决定研究 pydobc 本身。在 pyodbc github 开发站点中,我在 https://github.com/mkleehammer/pyodbc/wiki/Binding-Parameters 找到了一条有趣的信息。 ,尤其是在 写入 NULL 解决方案和变通方法 部分。

事实上,CSV 第一行的 17 个字段中有 3 个被我手动转换为 Pandas 中的“Nan”或 None。令我惊讶的是,将这些 None/Nan/NULL 替换为 上的有效值仅第一行 ,将速度提高到 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 不能仅从“无”推断使用哪个 NULL。为了克服这个限制,pyodbc 实现了两种方法:

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

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

    使用 .setinputsizes() 方法将字段的类型传递给 pyodbc.cursor 应该完全避免这个问题,但是现在 .setinputsizes() 在第一行中找到“无”时会被忽略。

    pyodbc 团队已意识到该问题,并将在 future 版本中进行修复。有关此错误的更多信息,请访问 https://github.com/mkleehammer/pyodbc/issues/741

    目前,唯一有效的解决方法是创建一个虚拟记录作为第一行(插入完成后将被删除),并为该类型提供一个代表值,以便 pyodbc 可以正确绑定(bind)正确的类型。

    此问题会影响所有使用 pyodbc 的包,包括 SQL Alchemy 和间接的 pandas。

    关于python - 使用 pyodbc 批量插入 + SQL Server 使用 None/Nan 很慢 + 解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61201530/

    相关文章:

    c# - 我将如何在一列数据库设计中创建多个类型ID

    python - Pyodbc 找不到 FreeTDS 驱动

    Python、Django 和 pyodbc : invalid characters

    Python 正则表达式。匹配和替换罗马数字

    sql - 在 SQL 表上插入数据...找不到数据

    c# - 如何加入with或条件?交叉连接正在创建 IS NULL where 子句

    python - 通过 Pyodbc 连接到 Oracle ODBC(32 位与 64 位)

    python - python 中的后台进程,终端上带有 -e 选项

    python - 为什么 sortBy() 无法在 Spark 中对数据进行均匀排序?

    python - 当循环结束时会发生什么?