在C++板块发了一帖,无人回复,希望在Oracle板块得到帮助。
大概描述下环境:数据源----->C++服务器----->Oracle Database
数据源来自于第三方,先发送到服务器,然后服务器保存到数据库,由于数据源是一条一条地发送到服务器,而且发送的速度非常快,目前服务器每收到一条数据就调用一次存储过程保存数据库,这样导致服务器收到的数据来不及处理,造成数据丢失,所以考虑采用批量插入数据库。希望有经验的同志们提供下指导,十万火急!Oracle批量插入
大概描述下环境:数据源----->C++服务器----->Oracle Database
数据源来自于第三方,先发送到服务器,然后服务器保存到数据库,由于数据源是一条一条地发送到服务器,而且发送的速度非常快,目前服务器每收到一条数据就调用一次存储过程保存数据库,这样导致服务器收到的数据来不及处理,造成数据丢失,所以考虑采用批量插入数据库。希望有经验的同志们提供下指导,十万火急!Oracle批量插入
1.对列满的时候要给对方返回错误,无法保证数据永远正常写入数据库。
2.你取出数据的时候,只要对列还有数据,就不停的读取出来存放到数组,直到一个批量数(如100条)。
3.然后以数组为输入参数批量插入到数据库。
PRO*C的一个例子:char* dyn_statement = "INSERT INTO emp (ename) VALUES (:ename_arr)" ;
char ename_arr[3][6] = {Tom","Dick","Harry"} ;
short ename_ind[3] = {0,-1,0} ;
int ename_len = 6, ename_type = 97, cnt = 2 ;
int empno_arr[3] = {8001, 8002, 8003} ;
int empno_len = 4 ;
int empno_type = 3 ;
int array_size = 3 ;
EXEC SQL FOR :array_size ALLOCATE DESCRIPTOR 'in' ;
EXEC SQL SET DESCRIPTOR 'in' COUNT = :cnt ;
EXEC SQL SET DESCRIPTOR 'in' VALUE 1 TYPE = :ename_type, LENGTH = :ename_len ;
EXEC SQL SET DESCRIPTOR 'in' VALUE 2 TYPE = :empno_type, LENGTH = :empno_len ;
EXEC SQL FOR :array_size SET DESCRIPTOR 'in' VALUE 1
DATA = :ename_arr, INDICATOR = :ename_ind ;
EXEC SQL FOR :array_size SET DESCRIPTOR 'in' VALUE 2
DATA = :empno_arr ;
EXEC SQL PREPARE s FROM :dyn_statement ;
EXEC SQL FOR :array_size EXECUTE s USING DESCRIPTOR 'in' ;
目前在网上了解到的方法:
1.用insert into t_its_batchinsert_test(test_id,test_name) select 'S001','ccc' from dual union all select 'S002','ccc' from dual....实现批量插入数据库,但是这种批量插入的条数受Oracle所支持的SQL语句最大长度影响。而且不知道这种方式相比一条一条插入是否会提高插入效率?2.将服务器队列中的数据先保存在文档中TXT或XML,然后另外开线程单独从文档中读取数据,写入磁盘速度不受数据库性能影响,但是数据的实时性变差了。还有其他方法没?求大神指点!顶顶顶!
1.对列满的时候要给对方返回错误,无法保证数据永远正常写入数据库。
2.你取出数据的时候,只要对列还有数据,就不停的读取出来存放到数组,直到一个批量数(如100条)。
3.然后以数组为输入参数批量插入到数据库。
PRO*C的一个例子:char* dyn_statement = "INSERT INTO emp (ename) VALUES (:ename_arr)" ;
char ename_arr[3][6] = {Tom","Dick","Harry"} ;
short ename_ind[3] = {0,-1,0} ;
int ename_len = 6, ename_type = 97, cnt = 2 ;
int empno_arr[3] = {8001, 8002, 8003} ;
int empno_len = 4 ;
int empno_type = 3 ;
int array_size = 3 ;
EXEC SQL FOR :array_size ALLOCATE DESCRIPTOR 'in' ;
EXEC SQL SET DESCRIPTOR 'in' COUNT = :cnt ;
EXEC SQL SET DESCRIPTOR 'in' VALUE 1 TYPE = :ename_type, LENGTH = :ename_len ;
EXEC SQL SET DESCRIPTOR 'in' VALUE 2 TYPE = :empno_type, LENGTH = :empno_len ;
EXEC SQL FOR :array_size SET DESCRIPTOR 'in' VALUE 1
DATA = :ename_arr, INDICATOR = :ename_ind ;
EXEC SQL FOR :array_size SET DESCRIPTOR 'in' VALUE 2
DATA = :empno_arr ;
EXEC SQL PREPARE s FROM :dyn_statement ;
EXEC SQL FOR :array_size EXECUTE s USING DESCRIPTOR 'in' ;
谢谢你的提供的方法,解释下你提出的3点:
1.第三方只管发,不收,肯定是丢失数据越少越好,得所以才考验服务器插入数据库的能力。
2.服务器插入操作数据库是同步的,操作完一次,才会去队列中去下一个数据插入,我可以有多个线程去队列中取数据插入,请问下,你提供的这种批量方法可以达到提高插入效率吗?
另外你在数据库生成个AWR报告,分析下数据库的问题。
建存储过程也可以定义输入参数为数组类型,然后使用FORALL批量处理,但我不了解ADO如何传入数组参数。DROP TABLE parts1;
CREATE TABLE parts1 (
pnum INTEGER,
pname VARCHAR2(15)
);
DROP TABLE parts2;
CREATE TABLE parts2 (
pnum INTEGER,
pname VARCHAR2(15)
);DECLARE
TYPE NumTab IS TABLE OF parts1.pnum%TYPE INDEX BY PLS_INTEGER;
TYPE NameTab IS TABLE OF parts1.pname%TYPE INDEX BY PLS_INTEGER;
pnums NumTab;
pnames NameTab;
iterations CONSTANT PLS_INTEGER := 50000;
t1 INTEGER;
t2 INTEGER;
t3 INTEGER;
BEGIN
FOR j IN 1..iterations LOOP -- populate collections
pnums(j) := j;
pnames(j) := 'Part No. ' || TO_CHAR(j);
END LOOP; t1 := DBMS_UTILITY.get_time; FOR i IN 1..iterations LOOP
INSERT INTO parts1 (pnum, pname)
VALUES (pnums(i), pnames(i));
END LOOP; t2 := DBMS_UTILITY.get_time; FORALL i IN 1..iterations
INSERT INTO parts2 (pnum, pname)
VALUES (pnums(i), pnames(i)); t3 := DBMS_UTILITY.get_time; DBMS_OUTPUT.PUT_LINE('Execution Time (secs)');
DBMS_OUTPUT.PUT_LINE('---------------------');
DBMS_OUTPUT.PUT_LINE('FOR LOOP: ' || TO_CHAR((t2 - t1)/100));
DBMS_OUTPUT.PUT_LINE('FORALL: ' || TO_CHAR((t3 - t2)/100));
COMMIT;
END;
/
更不清楚你们的网络情况,数据库服务器的性能等等。
只能和楼上的一样意见,考虑批次处理吧! 既然非常快,缓冲下其实更快,而不是浪费时间在传输,以及连接上,重新包装服务器的过程,以便批量处理要传送的信息。
还有你的OCCI执行的时候,是否总是保持连接打开?是否可能存在执行一次连接一次情况。