【问题标题】:Pandas .to_sql fails silently randomlyPandas .to_sql 随机失败
【发布时间】:2021-05-02 13:23:45
【问题描述】:

我有几个大熊猫数据框(大约 30k+ 行),需要每天将它们的不同版本上传到 MS SQL Server 数据库。我正在尝试使用 to_sql pandas 函数来做到这一点。有时,它会起作用。其他时候,它会失败 - 静默 - 就好像代码上传了所有数据,尽管没有上传一行。

这是我的代码:

class SQLServerHandler(DataBaseHandler):
    
    ...


    def _getSQLAlchemyEngine(self):
        '''
            Get an sqlalchemy engine
            from the connection string

            The fast_executemany fails silently:

            https://stackoverflow.com/questions/48307008/pandas-to-sql-doesnt-insert-any-data-in-my-table/55406717
        '''
        # escape special characters as required by sqlalchemy
        dbParams = urllib.parse.quote_plus(self.connectionString)
        # create engine
        engine = sqlalchemy.create_engine(
            'mssql+pyodbc:///?odbc_connect={}'.format(dbParams))

        return engine

    @logExecutionTime('Time taken to upload dataframe:')
    def uploadData(self, tableName, dataBaseSchema, dataFrame):
        '''
            Upload a pandas dataFrame
            to a database table <tableName>
        '''
        engine = self._getSQLAlchemyEngine()

        dataFrame.to_sql(
            tableName,
            con=engine,
            index=False,
            if_exists='append',
            method='multi', 
            chunksize=50,              
            schema=dataBaseSchema)

将方法切换到None 似乎可以正常工作,但上传数据需要花费大量时间(30 多分钟)。每天有多个这种大小的表(大约 20 个)会放弃这种解决方案。

建议的解决方案here 将架构添加为参数不起作用。也不会创建 sqlalchemy 会话并将其传递给 con 参数和 session.get_bind()

我正在使用:

  • 适用于 SQL Server 的 ODBC 驱动程序 17
  • 熊猫 1.2.1
  • sqlalchemy 1.3.22
  • pyodbc 4.0.30

有没有人知道如何让它在失败时引发异常?

或者为什么它没有上传任何数据?

【问题讨论】:

  • 对于 MySQL,我使用 LOAD DATA INFILE 函数插入大量数据。它比插入语句快 50 倍 MS SQL 具有类似的功能:docs.microsoft.com/fr-fr/sql/t-sql/statements/…
  • 尝试使用create_engine(…, fast_executemany=True).to_sql(…, method=None)
  • @GordThompson,不幸的是,这也默默地失败了
  • 您是否有一个测试环境,您可以在其中工作而不会弄乱生产?如果是这样,那么您可以使用 .create_engine(…, echo=True) 查看发送到服务器的 SQL 语句和/或使用 ODBC tracing 查看在该级别的对话中是否有任何问题。

标签: python-3.x pandas sqlalchemy pyodbc


【解决方案1】:

反驳this answer,如果to_sql() 成为中所述问题的受害者

SQL Server does not finish execution of a large batch of SQL statements

那么它必须构造大型匿名代码块的形式

-- Note no SET NOCOUNT ON;
INSERT INTO gh_pyodbc_262 (id, txt) VALUES (0, 'row0');
INSERT INTO gh_pyodbc_262 (id, txt) VALUES (1, 'row1');
INSERT INTO gh_pyodbc_262 (id, txt) VALUES (2, 'row2');
…

这不是to_sql() 正在做的事情。如果是这样,那么它将在 1_000 行以下开始失败,至少在 SQL Server 2017 Express Edition 上:

import pandas as pd
import pyodbc
import sqlalchemy as sa

print(pyodbc.version)  # 4.0.30

table_name = "gh_pyodbc_262"
num_rows = 400
print(f" num_rows: {num_rows}")  # 400

cnxn = pyodbc.connect("DSN=mssqlLocal64", autocommit=True)
crsr = cnxn.cursor()

crsr.execute(f"TRUNCATE TABLE {table_name}")

sql = "".join(
    [
        f"INSERT INTO {table_name} ([id], [txt]) VALUES ({i}, 'row{i}');"
        for i in range(num_rows)
    ]
)
crsr.execute(sql)

row_count = crsr.execute(f"SELECT COUNT(*) FROM {table_name}").fetchval()
print(f"row_count: {row_count}")  # 316

使用to_sql() 进行相同的操作也有效

import pandas as pd
import pyodbc
import sqlalchemy as sa

print(pyodbc.version)  # 4.0.30

table_name = "gh_pyodbc_262"
num_rows = 400
print(f" num_rows: {num_rows}")  # 400

df = pd.DataFrame(
    [(i, f"row{i}") for i in range(num_rows)], columns=["id", "txt"]
)

engine = sa.create_engine(
    "mssql+pyodbc://@mssqlLocal64", fast_executemany=True
)

df.to_sql(
    table_name,
    engine,
    index=False,
    if_exists="replace",
)

with engine.connect() as conn:
    row_count = conn.execute(
        sa.text(f"SELECT COUNT(*) FROM {table_name}")
    ).scalar()
    print(f"row_count: {row_count}")  # 400

确实适用于数千甚至数百万行。 (我成功测试了 5_000_000 行。)

【讨论】:

    【解决方案2】:

    好的,这似乎是 SQL Server 本身的问题。

    SQL Server does not finish execution of a large batch of SQL statements

    【讨论】:

      猜你喜欢
      • 2019-04-21
      • 2015-07-31
      • 1970-01-01
      • 2015-08-04
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多