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;
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;
每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
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; 至于批量插入数据时报错导致后面的数据无法插入,这时就需要捕获插入异常,发现插入异常,就只能用循环一条条地插入,找到导致异常的那条记录,记下日志。
下面是我写库线程的执行代码:
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;
我觉得你应当用事务,把FSQLs的语句拼到一个事务中,然后将事务定时提交,
下面是我写库线程的执行代码:
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;
程序可以考虑一定条数后再提交sql
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;
触发器还是一样工作的sSQL如果是'insert ....;
insert ...;
...
insert ...;'
,而oracle能支持,就行了
如果不是,建议做个临时表,最好这个表在单独的表空间上,并且这个表空间要针对联机交易业务类型进行优化。
然后做个oracle调度计划,定时将临时表的输入插入到正式表。
这个和银行系统的白天联机交易频繁的单笔交易,晚上批量办理结算业务有点类似像一个道理。
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
finally
FSQLs.Delete(0); FSQLs是TStringList???
如果是,在每秒几百条string的操作下,而且在FSQLs量可能有上千上万的堆积情况下,那FSQLs.Delete(0)操作是很慢的。建议:自己写个先进先出队列。最起码将这个可能影响性能的问题先排除。
# (老之)能否详细说一下,突然发现,不光是insert,还要执行update等操作可以不加入事务,因为绝大多数是insert动作,如果insert失败,不需要回滚,可能的话能将出错sql写日志就行了,update同样,出错记录一下就行,不需要任何回滚动作
可以选择适当的条件提交事务。另外,你的sql用绑定变量了吗,索引什么的都建好了吗,这些也是很关键的。
我倾向于这个方法,因为一开始也是这么想的
但有几个问题
1、在delphi里怎么实现,我在网上搜了一下,delphi中调用oci接口可以用doa控件,但具体怎么调用还不知道
2、一次提交上去后,如果第一条sql就出错,那后面还没执行的sql是不是就丢了?我所希望的出错解决方法就是一条sql出错,只记录那条sql,以供以后查询,后面的sql继续执行
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;
至于批量插入数据时报错导致后面的数据无法插入,这时就需要捕获插入异常,发现插入异常,就只能用循环一条条地插入,找到导致异常的那条记录,记下日志。