我在一单元中写有如下过程:
procedure file2table(filename: string);
var
f: textfile;
ts: TStrings;
i, r: integer;
s: string;
begin
with dmsettle do
begin
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('truncate table usr10sub');
ADOQuery1.ExecSQL;
finally
ADOQuery1.Close;
end;
try
i := 0;
ADOTable1.TableName := 'usr10sub';
ADOTable1.Open;
//ts := TStringList.Create;
assignfile(f, filename);
reset(f);
while not eof(f) do
begin
readln(f, s);
if s = '' then break;
inc(i);
subscriber.suiProgressBar1.Position := i;
//subscriber.suiProgressBar1.Update;
ts := TStringList.Create;
extractstrings([chr(01)], [chr(44), chr(39)], pansichar(s), ts);
try
//ADOTable1.Append;
ADOTable1.Insert;
for r := 0 to (ADOTable1.FieldCount - 1) do
begin
case ADOTable1.Fields[r].DataType of
ftFloat, ftInteger, ftSmallint, ftWord:
ADOTable1.Fields[r].AsFloat := StrToFloat(ts.Strings[r]);
else
ADOTable1.Fields[r].AsString := ts.strings[r];
end;
end;
ADOTable1.Post;
except
showmessage(s);
break;
end;
ts.Free;
end;
finally
//ts.Free;
closefile(f);
ADOTable1.Close;
end;
end;
end;
目的是想把文本文件(大约有30万行,以chr(01)分隔)导入表中,已正常将记录导入到表中,但有一个不明白的地方,程序运行时损耗大量的内存,其中sqlserver也一样损耗大量内存,并且导入速度很慢。各位高手,能说说怎样改进吗?使程序损少量内存!!!
procedure file2table(filename: string);
var
f: textfile;
ts: TStrings;
i, r: integer;
s: string;
begin
with dmsettle do
begin
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('truncate table usr10sub');
ADOQuery1.ExecSQL;
finally
ADOQuery1.Close;
end;
try
i := 0;
ADOTable1.TableName := 'usr10sub';
ADOTable1.Open;
//ts := TStringList.Create;
assignfile(f, filename);
reset(f);
while not eof(f) do
begin
readln(f, s);
if s = '' then break;
inc(i);
subscriber.suiProgressBar1.Position := i;
//subscriber.suiProgressBar1.Update;
ts := TStringList.Create;
extractstrings([chr(01)], [chr(44), chr(39)], pansichar(s), ts);
try
//ADOTable1.Append;
ADOTable1.Insert;
for r := 0 to (ADOTable1.FieldCount - 1) do
begin
case ADOTable1.Fields[r].DataType of
ftFloat, ftInteger, ftSmallint, ftWord:
ADOTable1.Fields[r].AsFloat := StrToFloat(ts.Strings[r]);
else
ADOTable1.Fields[r].AsString := ts.strings[r];
end;
end;
ADOTable1.Post;
except
showmessage(s);
break;
end;
ts.Free;
end;
finally
//ts.Free;
closefile(f);
ADOTable1.Close;
end;
end;
end;
目的是想把文本文件(大约有30万行,以chr(01)分隔)导入表中,已正常将记录导入到表中,但有一个不明白的地方,程序运行时损耗大量的内存,其中sqlserver也一样损耗大量内存,并且导入速度很慢。各位高手,能说说怎样改进吗?使程序损少量内存!!!
预处理文件的时候用FileStream或FileMapping,不要一次把所有数据读取进来,读进来一部分处理一部分再写入一部分
这个SQL文本难道会有问题?
var
f: textfile;
ts: TStrings;
i, r: integer;
s: string;
List:TStringList;
begin
with dmsettle do
begin
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('truncate table usr10sub');
ADOQuery1.ExecSQL;
finally
ADOQuery1.Close;
end; List := TStringList.Create;
try
assignfile(f, filename);
reset(f);
List.Clear;
while not eof(f) do
begin
readln(f, s);
if s = '' then break;
subscriber.suiProgressBar1.Position := i;
extractstrings([chr(01)], [chr(44), chr(39)], pansichar(s), ts);
try
List.Add('insert... '); //此处是添加记录的SQL语句,由你自己填写
except
showmessage(s);
break;
end; //此处是每读入1000记录,则一次性添加,你也可以自己调整,每2000条记录一次性添加,但这会增加内存耗用的
//注意这种方式,能极大地加快添加数据的速度,此处是关键点
if List.Count>1000 then
begin
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.AddStrings(List);
ADOQuery1.ExecSQL;
List.Clear;
end;
end; if List.Count>0 then
begin
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.AddStrings(List);
ADOQuery1.ExecSQL;
List.Clear;
end; finally
List.Clear;
FreeAndNil(List);
closefile(f);
ADOTable1.Close;
end;
end;
end;
所以有些地方要效率,就得自己写。效率和方便是对用户说的,对编程的人来说有时是两者不可兼得的。
那个 if List.Count>1000 then 应该换成 if 读入的记录数>1000 then
MS已经给出了大批量导入/导出的解决方案!
--摘自MSSQL联机帮助!A. 使用管道从文件导入数据
此示例将订单详细信息从指定的数据文件导入 AdventureWorks.Sales.SalesOrderDetail 表,并使用竖线 (|) 作为字段终止符,使用 |\n 作为行终止符。BULK INSERT AdventureWorks.Sales.SalesOrderDetail
FROM 'f:\orders\lineitem.tbl'
WITH
(
FIELDTERMINATOR =' |',
ROWTERMINATOR =' |\n'
)
这样没有问题。你可能误会了我的意思,我在回复2楼朋友时已经说明了开始时也考虑了用SQL语句的方法,就是因为太繁锁而选用ADOTABLE组件。
刚才写漏了:含有chr(63)时...
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Text := 'select top 0 * from usr10sub';
ADOQuery1.Open;然后把你后面代码的ADOTable1换成ADOQuery1, 然后每过1000笔再执行一次以上的代码,这样Local内存和SQL Server的内存应该都会降下来。
难得1楼还比较细心,考虑文本内容较多,分批次来读。
“ADOTable1.Fields[r].AsFloat := StrToFloat(ts.Strings[r]); ”
的代码, 就推荐一下, 总是比ADOTable一直增加数据强, 呵呵。
ADOQuery
ADOTable
procedure file2table(filename: string);
var
f: textfile;
i, r: integer;
s, fixsql, varsql: string;
ts: TStrings;
ft: array of TFieldType;
begin
if not fileexists(filename) then exit;
with dmsettle do
begin
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('truncate table usr10sub');
ADOQuery1.ExecSQL;
finally
ADOQuery1.Close;
end;
//字段列表
ts := TStringList.Create;
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('select * from usr10sub');
ADOQuery1.Open;
ADOQuery1.GetFieldNames(ts);
setlength(ft, (ADOQuery1.FieldCount - 1));
for i := 0 to (ADOQuery1.FieldCount - 1) do
ft[i] := ADOQuery1.Fields[i].DataType;
finally
ADOQuery1.Close;
end;
//组SQL固定部份语句
fixsql := format('insert into usr10sub(%s', [ts.Strings[0]]);
for i := 1 to (ts.Count - 1) do
fixsql := format('%s, %s', [fixsql, ts.Strings[i]]);
fixsql := format('%s)', [fixsql]);
i := 0;
try
assignfile(f, filename);
reset(f);
while not eof(f) do
begin
readln(f, s);
if s = '' then break;
inc(i);
subscriber.Label1.Caption := format('正在全量更新 usr10sub 表[%d / %d] ... ', [i, subscriber.suiProgressBar1.Max]);
subscriber.Label1.Update;
subscriber.suiProgressBar1.Position := i;
subscriber.suiProgressBar1.Update;
ts.Clear;
extractstrings([chr(01)], [chr(44), chr(39)], pansichar(s), ts);
case ft[0] of
ftInteger, ftFloat, ftWord, ftSmallint, ftBCD:
varsql := format('values(%s', [ts.Strings[0]]);
else
varsql := format('values(''%s''', [ts.Strings[0]]);
end;
for r := 1 to (ts.Count - 1) do
begin
case ft[r] of
ftInteger, ftFloat, ftWord, ftSmallint, ftBCD:
varsql := format('%s, %s', [varsql, ts.Strings[r]]);
else
varsql := format('%s, ''%s''', [varsql, ts.Strings[r]]);
end;
end;
varsql := format('%s)', [varsql]);
try
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add(fixsql);
ADOQuery1.SQL.Add(varsql);
ADOQuery1.ExecSQL;
except
MessageBox(0, PAnsiChar(format('SUBUNI: %s [%d]', [ADOConnection1.Errors[0].Description, ADOConnection1.Errors[0].NativeError])), PAnsiChar(subscriber.Caption), MB_OK + MB_ICONERROR);
break;
end;
end;
finally
ADOQuery1.Close;
closefile(f);
end;
end;
ts.Free;
end;
很感谢1楼、2楼、... 9楼、10楼等的朋友,是他(她)们给了我很多的帮助,谢谢你们!