读书人

如何样向oracle高速插入记录

发布时间: 2012-07-19 16:02:19 作者: rapoo

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

[解决办法]
如果是mssql,可以每几十或几百条生成一个sql,一次提交
[解决办法]
你的FSQLs在哪?需要作保护么?
我觉得你应当用事务,把FSQLs的语句拼到一个事务中,然后将事务定时提交,
[解决办法]
建议干掉触发器,慢得要死
[解决办法]
你这样写是一条一条记录的去提交的,可以改为插入全部完成后才提交。另外,建议你把插入的部分放在DB的存储过程里面,并在存储过程里面捕捉所有的异常,你可以把有异常的信息记录到一个ERRORTABLE里面。
[解决办法]

探讨
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;//while

end;

[解决办法]
触发器里面写太多东西会造成以后很难维护,因为如果解发器报错了,你在前台的程序可能捕捉不到异常,结果找半天才发现是DB里面解发器的问题,真是郁闷。如果可以把触发器里面做的东西写到前台程序的话会好一点,比如插入的时候触发器做了什么就在前台里面完成就好了,不过效率上面可能会差一些。
[解决办法]
优化和检查触发器吧,这样速度的话触发器会对性能有一定影响,但是插入是肯定能进去,可能触发器执行出错了


程序可以考虑一定条数后再提交sql
[解决办法]
一次性提交n条,省掉的是n-1次的提交、分析过程,效率更高而已
触发器还是一样工作的

sSQL如果是'insert ....;
insert ...;
...
insert ...;'
,而oracle能支持,就行了
[解决办法]
触发器是做什么的?一般有大数据量时,触发器会影响性能特别费资源。

接收数据时可以先把数据放在一个中间表中,然后后台有一个负责向数据库的正式表insert的线程,将他们分开来做。

[解决办法]
实时插入的数据是不是要求在其他前段系统也能实时查询到?
如果不是,建议做个临时表,最好这个表在单独的表空间上,并且这个表空间要针对联机交易业务类型进行优化。
然后做个oracle调度计划,定时将临时表的输入插入到正式表。
这个和银行系统的白天联机交易频繁的单笔交易,晚上批量办理结算业务有点类似像一个道理。
[解决办法]
你最好是加一个数据处理队列,这样在不死机的情况下是不会丢失数据的。然后再怎么处理数据 想怎么处理就怎么处理
[解决办法]
每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
[解决办法]
还有这个操作

sSQL := FSQLs.Strings[0];
finally
FSQLs.Delete(0);

FSQLs是TStringList???
如果是,在每秒几百条string的操作下,而且在FSQLs量可能有上千上万的堆积情况下,那FSQLs.Delete(0)操作是很慢的。



建议:自己写个先进先出队列。最起码将这个可能影响性能的问题先排除。
[解决办法]
有遇到过类似的情况,一条条插入数据的效率很低。 解决办法是用oracle的OCI接口批量提交数据, 建立一个数组达到一定数据量就一次提交上去。

[解决办法]
不加事务如何提交到数据库,oracle数据库可以置成自动提交(可能就是你所说的不加事务),但这样每一条都会提交一次,这样效率会更低。
可以选择适当的条件提交事务。

另外,你的sql用绑定变量了吗,索引什么的都建好了吗,这些也是很关键的。
[解决办法]
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;

Delphi(Pascal) code
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; 

读书人网 >.NET

热点推荐