现在程序每秒大概会收到几百条数据,要求将收到的数据全都插入到数据库中,在数据插入时会有一个触发器触发,其它没有任何处理。
我现在是开个线程,收到一条就实时插入一条,数据量小的情况下还好一点,大数据量就会出现数据丢失的情况,而且这样明显效率不高。
请各位给个思路,有具体代码更好。

解决方案 »

  1.   

    如果是mssql,可以每几十或几百条生成一个sql,一次提交
      

  2.   

    3楼的朋友能否详细说一下
    下面是我写库线程的执行代码:
    procedure TWriteDBThread.Execute;
    var
      sErrMsg, sSQL: string;
    begin
      while not Terminated do
      begin
        if FSQLs.Count > 0 then
        begin
          try
            sSQL := FSQLs.Strings[0];
            sErrMsg := '';
            try
              ExecSQL(sSQL, sErrMsg);
            except
            end;//try..except          finally
            FSQLs.Delete(0);
          end;
        end;
        
        sleep(2);
      end;//whileend;
      

  3.   

    你的FSQLs在哪?需要作保护么?
    我觉得你应当用事务,把FSQLs的语句拼到一个事务中,然后将事务定时提交,
      

  4.   

    你这样写是一条一条记录的去提交的,可以改为插入全部完成后才提交。另外,建议你把插入的部分放在DB的存储过程里面,并在存储过程里面捕捉所有的异常,你可以把有异常的信息记录到一个ERRORTABLE里面。
      

  5.   

    3楼的朋友能否详细说一下 
    下面是我写库线程的执行代码: 
    procedure TWriteDBThread.Execute; 
    var 
      sErrMsg, sSQL: string; 
    begin 
      while not Terminated do 
      begin 
        if FSQLs.Count > 0 then 
        begin 
          try 
            //sSQL := FSQLs.Strings[0]; 
            sErrMsg := ''; 
            try 
              ExecSQL(FSQLs.text, sErrMsg); //一次执行多个sql语句
            except 
            end;//try..except          finally 
            FSQLs.clear; //Delete(0); 
          end; 
        end; 
        
        sleep(2); 
      end;//while end;
      

  6.   

    优化和检查触发器吧,这样速度的话触发器会对性能有一定影响,但是插入是肯定能进去,可能触发器执行出错了
    程序可以考虑一定条数后再提交sql
      

  7.   

    触发器肯定是不能删掉的,牵扯面太大
    1、一定条数再提交sql会不会影响到触发器的执行?因为要求每条记录写进去的时候都必须执行一下那个触发器。2、怎么一次性提交多条sql
    上面我的ExecSQL(FSQLs.text, sErrMsg);执行SQL语句是这样的:
        with TOraSQL.Create(nil) do
        try
          Session := OraSession;
          try
            SQL.Clear;
            SQL.Text:=sSQL;  //执行的时候还是一条条执行
            Execute;
          except
          end;
        finally
          free;
        end;    OraSession.Commit;
      

  8.   

    一次性提交n条,省掉的是n-1次的提交、分析过程,效率更高而已
    触发器还是一样工作的sSQL如果是'insert ....;
    insert ...;
    ...
    insert ...;'
    ,而oracle能支持,就行了
      

  9.   

    触发器是做什么的?一般有大数据量时,触发器会影响性能特别费资源。接收数据时可以先把数据放在一个中间表中,然后后台有一个负责向数据库的正式表insert的线程,将他们分开来做。
      

  10.   

    实时插入的数据是不是要求在其他前段系统也能实时查询到?
    如果不是,建议做个临时表,最好这个表在单独的表空间上,并且这个表空间要针对联机交易业务类型进行优化。
    然后做个oracle调度计划,定时将临时表的输入插入到正式表。
    这个和银行系统的白天联机交易频繁的单笔交易,晚上批量办理结算业务有点类似像一个道理。
      

  11.   

    每N秒执行一次,每次执行,限制100个数据,类似:insert into mytable(field1, f2, f3)
       select fieldvalue1, fv2, fv3 from dual union all
       select fieldvalue1, fv2, fv3 from dual union all
       select fieldvalue1, fv2, fv3 from dual union all
       ...
       select fieldvalue1, fv2, fv3 from dual
    这种运行多条语句,速度快很多。
    insert into mytable(field1, f2, f3)   
    select fieldvalue1, fv2, fv3 from dual
    如果还是处理不过来,建议用Oracle的外部导入工具。
    一般SQL语句导入相对操作慢,用外部工具: sqlldr,我试过,30秒可以导入几十万条的数据(没有触发器)具体操作可以google: oracle sqlldr
      

  12.   

    还有这个操作       sSQL := FSQLs.Strings[0]; 
          finally 
            FSQLs.Delete(0); FSQLs是TStringList???
    如果是,在每秒几百条string的操作下,而且在FSQLs量可能有上千上万的堆积情况下,那FSQLs.Delete(0)操作是很慢的。建议:自己写个先进先出队列。最起码将这个可能影响性能的问题先排除。
      

  13.   

    有遇到过类似的情况,一条条插入数据的效率很低。 解决办法是用oracle的OCI接口批量提交数据, 建立一个数组达到一定数据量就一次提交上去。
      

  14.   

    to # liangqingzhi
    # (老之)能否详细说一下,突然发现,不光是insert,还要执行update等操作可以不加入事务,因为绝大多数是insert动作,如果insert失败,不需要回滚,可能的话能将出错sql写日志就行了,update同样,出错记录一下就行,不需要任何回滚动作
      

  15.   

    不加事务如何提交到数据库,oracle数据库可以置成自动提交(可能就是你所说的不加事务),但这样每一条都会提交一次,这样效率会更低。
    可以选择适当的条件提交事务。另外,你的sql用绑定变量了吗,索引什么的都建好了吗,这些也是很关键的。
      

  16.   


    我倾向于这个方法,因为一开始也是这么想的
    但有几个问题
    1、在delphi里怎么实现,我在网上搜了一下,delphi中调用oci接口可以用doa控件,但具体怎么调用还不知道
    2、一次提交上去后,如果第一条sql就出错,那后面还没执行的sql是不是就丢了?我所希望的出错解决方法就是一条sql出错,只记录那条sql,以供以后查询,后面的sql继续执行
      

  17.   

    delphi里用的是odac控件,可以参考一下下面批量插入数据的做法:表名
    create table TEST_RY
    (
      RYMC VARCHAR2(20),
      AGE  NUMBER(2),
      VAL  NUMBER
    )类型
    create or replace type TEST_RY_TYPE is object
      (
        mc varchar(20),
        age number(2),
        val number
      )create or replace type TEST_RY_ARR is table of TEST_RY_TYPE
    存储过程
    create or replace procedure TEST_ADD_RY(valarr in TEST_RY_ARR) as
    begin
      insert into TEST_RY(Rymc, age, val)
       select mc, age, val from table(valarr);
    end;
    uses OraObjects;var
      oNestTable: TOraNestTable;
    begin
      with OraQuery1 do
      begin
        Close;
        sql.Clear;
        SQL.Text :=  ' begin '
                   + ' TEST_ADD_RY(:test); '
                   + ' end; ';    with OraQuery1.ParamByName('test').AsArray do
        begin
           ObjectType:=TOraType.Create(OraSession1.OCISvcCtx,'TEST_RY_ARR');
           ItemAsObject[0].AttrAsString['MC']:= 'Bruce';
           ItemAsObject[0].AttrAsInteger['age']:= 18;
           ItemAsObject[0].AttrAsInteger['val']:= 25;
           ItemAsObject[1].AttrAsString['MC']:= 'Tom';
           ItemAsObject[1].AttrAsInteger['age']:= 17;
           ItemAsObject[1].AttrAsInteger['val']:= 20;
           ItemAsObject[2].AttrAsString['MC']:= 'John';
           ItemAsObject[2].AttrAsInteger['age']:= 22;
           ItemAsObject[2].AttrAsInteger['val']:= 31;
        end;
        ExecSQL;
        Close;
      end;
    end;
    至于批量插入数据时报错导致后面的数据无法插入,这时就需要捕获插入异常,发现插入异常,就只能用循环一条条地插入,找到导致异常的那条记录,记下日志。