在C++板块发了一帖,无人回复,希望在Oracle板块得到帮助。
大概描述下环境:数据源----->C++服务器----->Oracle Database
数据源来自于第三方,先发送到服务器,然后服务器保存到数据库,由于数据源是一条一条地发送到服务器,而且发送的速度非常快,目前服务器每收到一条数据就调用一次存储过程保存数据库,这样导致服务器收到的数据来不及处理,造成数据丢失,所以考虑采用批量插入数据库。希望有经验的同志们提供下指导,十万火急!Oracle批量插入

解决方案 »

  1.   


    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' ;
      

  2.   

    目前存在的问题是,服务器队列满了,数据就会丢失,不是大忌,所以需要提高插入数据的效率。
    目前在网上了解到的方法:
    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,然后另外开线程单独从文档中读取数据,写入磁盘速度不受数据库性能影响,但是数据的实时性变差了。还有其他方法没?求大神指点!顶顶顶!
      

  3.   


    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.服务器插入操作数据库是同步的,操作完一次,才会去队列中去下一个数据插入,我可以有多个线程去队列中取数据插入,请问下,你提供的这种批量方法可以达到提高插入效率吗?
      

  4.   

    对于大数据量处理,批量操作会比单条操作效率高得多,你如果是使用OCCI,请参考OCCI文档的批量处理说明。
    另外你在数据库生成个AWR报告,分析下数据库的问题。
      

  5.   

    OCCI是什么东东?没听过,数据库方面的我不了解,服务器操作数据库使用的是WINDOWS 提供的ADO COM组件提供的接口,操作数据库建表,写存储过程什么的用的是pl/sql developer客户端。
      

  6.   

    这是PL/SQL文档上的批量处理例子,你可以看出批量跟单条的效率差别。
    建存储过程也可以定义输入参数为数组类型,然后使用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;
    /
      

  7.   

    不清楚,你的实时性要求非常高的具体所指,也不清楚你调用的过程是如何写的,
    更不清楚你们的网络情况,数据库服务器的性能等等。
    只能和楼上的一样意见,考虑批次处理吧!  既然非常快,缓冲下其实更快,而不是浪费时间在传输,以及连接上,重新包装服务器的过程,以便批量处理要传送的信息。
    还有你的OCCI执行的时候,是否总是保持连接打开?是否可能存在执行一次连接一次情况。