【发布时间】:2013-12-12 17:11:35
【问题描述】:
我的 .NET 应用程序接收到一个数据流,我需要将其转储到 Oracle 数据库中的几个表中。我有一个内部队列,它对数据进行排队,并且从队列中读取的几个线程将其转换为相应的插入语句。我每秒接收大约 10 个数据项,但每秒可能会爆发超过 100 个数据项。
我的第一种方法是把每一个数据项,转换成对应的插入语句,一个一个地执行。但是,这太慢了,因为每次插入都需要往返数据库。
我的下一个方法是将插入批处理成最多 50 个的组,具体取决于队列中有多少项,然后将它们包装到一个 begin-end 块中,然后将其推送到数据库中,如下所示:
begin
insert into MyTable (col1, col2, col3...) values (123, 'data1', 'data2', ...);
insert into MyTable (col1, col2, col3...) values (456, 'dataX', 'dataY', ...);
insert into MyTable (col1, col2, col3...) values (789, 'dataA', 'dataB', ...);
-- variable number inserts...
end;
这显着提高了性能,我很高兴。然后我们的 Oracle 人员来找我,告诉我我正在杀死他的数据库,因为我正在发送大量独特的 SQL 语句,Oracle 每次都必须解析和缓存这些语句。最终,甲骨文崩溃了。建议是始终对绑定变量使用相同的 SQL 语句,这样就不必每次都对其进行解析。
但是,这会让我回到最初遇到的问题,即我必须一次运行每个插入语句,并使用绑定变量,以使语句相同。
insert into MyTable (col1, col2, col3...) values (:val1, :val2, :val3, ...);
我可以尝试将多个插入合并到一个开始-结束块中,但这会导致 SQL 语句都是唯一的问题。
begin
insert into MyTable (col1, col2, col3...) values (:val11, :val12, :val13, ...);
insert into MyTable (col1, col2, col3...) values (:val21, :val22, :val23, ...);
insert into MyTable (col1, col2, col3...) values (:val31, :val32, :val33, ...);
...
end;
我该怎么办?使用绑定变量一一插入语句,但使用大量线程?我应该将它们写入 CSV 文件并使用 SQL Loader 吗?但是我将如何处理 CLOB 列?是否应该将插入内容包装在存储过程中,然后使用我的批处理方法?
我觉得这一定是一个很普遍的问题,对于这种情况一定有某种最佳实践。
【问题讨论】:
-
在 SQL 中可以有多个值 (1,2), (2,3) ... 这减少了唯一语句的数量和锁的数量。有 1000 个限制和一个甜蜜点。怀疑与 Oracle 相同。还有TVP和Drapper。但我的经验是使用 SQL,所以只能发表评论。
-
根本不是我的领域,但这里有一个关于使用数组绑定在 ODP.Net 中提高批量插入效率的页面:dotnetslackers.com/articles/ado_net/…