SQLAlchemy在Oracle数据库中大容量插入blob数据



我正试图在带有Oracle DB的SQLAlchemy中进行大容量插入操作,该操作插入带有blob数据的60k行。

这就是我的表和代码的样子:

CREATE TABLE datatables (
id INTEGER NOT NULL, 
table_name VARCHAR2(50 CHAR), 
row_id VARCHAR2(50 CHAR), 
row_data BLOB, 
PRIMARY KEY (id)
)
with Session() as session:
session.execute(
DataTables.__table__.insert(),
datas
)

其中DataTables是表的SQLAclhemy类映射,datas是类似于{'id': 1, 'table_name': 'app', 'row_id': 'version', 'row_data': '....'}的dict列表

有了这样的代码,我得到了这个sql语句

sqlalchemy.engine.Engine INSERT INTO datatables (id, table_name, row_id, row_data) VALUES (:id, :table_name, :row_id, :row_data)
sqlalchemy.engine.Engine [generated in 0.14718s] [{'id': 1, 'table_name': 'app', 'row_id': 'version', 'row_data': b'some_data'}, ...]

它一直在运行,即使在30分钟后它也没有完成。当我启用DPI跟踪时,有很多这样的行:

ODPI [12912] 2021-12-18 00:07:36.019: ref 0000019C3D15C5B0 (dpiConn) -> 8
ODPI [12912] 2021-12-18 00:07:36.020: ref 0000019C413F0C20 (dpiLob) -> 1 [NEW]
ODPI [12912] 2021-12-18 00:07:36.020: ref 0000019C3D15C5B0 (dpiConn) -> 9
ODPI [12912] 2021-12-18 00:07:36.020: ref 0000019C413F1990 (dpiLob) -> 1 [NEW]

但是,如果我使用原始sql:

session.execute('insert into DATATABLES (id, table_name, row_id, row_data) values (:id, :table_name, :row_id, :row_data)', datas)

DPI跟踪更改为:

ODPI [00796] 2021-12-18 00:14:55.246: ref 000002486741EAF0 (dpiVar) -> 0
ODPI [00796] 2021-12-18 00:14:55.246: ref 00000248617D2DF0 (dpiConn) -> 6
ODPI [00796] 2021-12-18 00:14:55.246: fn end dpiVar_release(000002486741EAF0) -> 0
ODPI [00796] 2021-12-18 00:14:55.246: fn start dpiVar_setFromBytes(000002486741EBB0)
ODPI [00796] 2021-12-18 00:14:55.247: fn end dpiVar_setFromBytes(000002486741EBB0) -> 0
ODPI [00796] 2021-12-18 00:14:55.247: fn start dpiVar_setFromBytes(0000024864E5FDE0)
ODPI [00796] 2021-12-18 00:14:55.247: fn end dpiVar_setFromBytes(0000024864E5FDE0) -> 0
ODPI [00796] 2021-12-18 00:14:55.247: fn start dpiVar_setFromBytes(0000024864E601A0)
ODPI [00796] 2021-12-18 00:14:55.247: fn end dpiVar_setFromBytes(0000024864E601A0) -> 0

并且在15秒内完成批量插入。

SQL语句在这两种情况下都是相同的。为什么它的工作原理不同?当然,我可以使用原始sql,但我想使用DataTables.__table__.insert(),因为如果表或列的名称会更改,我不需要每次都为此修复sql。

此类问题最好作为SQLAlchemy中的错误报告,您可以在以下位置进行报告:https://github.com/sqlalchemy/sqlalchemy/issues/否则我们完全没有意识到这个问题。

在这种情况下,我们已经收到了这个问题的警告,并将寻求根据SQLAlchemy 2.0的cx_oracle开发人员更新我们的LOB设置,该设置在https://github.com/sqlalchemy/sqlalchemy/issues/7494

最新更新