我需要循环抛出tstringlist并为每个项执行insert。现在我的代码是:
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p2').Value := TS2[i];
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
aqZapisz.SQL.Clear;
end;
但插入时间约为2分钟,TS2中有1700个项目。我怎样才能提高速度?
答案 0 :(得分:1)
每次循环都不要替换你的SQL语句。在循环开始之前设置一次,然后只更新循环内的参数。
aqZapisz.SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p2').Value := TS2[i];
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
end;
答案 1 :(得分:1)
您可以使用
提高速度单笔交易
Connection.StartTransaction;
try
// Send the data to the server
Connection.Commit;
except
ConnectionRollback;
end;
将数据拆分为固定和动态部分,因此您不必一次又一次地向服务器发送相同的数据。将固定部分存储到临时表中,并将其用于包含动态数据的每个插入
快速解决方案
aqZapisz.Connection.StartTransaction;
try
aqZapisz.SQL.Text :=
'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, ' +
'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
aqZapisz.Parameters.ParamByName( 'p1' ).Value := idk;
aqZapisz.Parameters.ParamByName( 'p3' ).Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName( 'p4' ).Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName( 'p5' ).Value := id_grupy;;
aqZapisz.Parameters.ParamByName( 'p6' ).Value := id_rodzaju;
aqZapisz.Parameters.ParamByName( 'p7' ).Value := id_typu;
aqZapisz.Parameters.ParamByName( 'p8' ).Value := DateToStr( zxDateDok.Date );
aqZapisz.Parameters.ParamByName( 'p9' ).Value := DateToStr( zxDatePlat.Date );
aqZapisz.Parameters.ParamByName( 'p10' ).Value := DateToStr( zxDateKsieg.Date );
aqZapisz.Parameters.ParamByName( 'p11' ).Value := IntToStr( Integer( MonthOf( zxDateKsieg.Date ) ) );
aqZapisz.Parameters.ParamByName( 'p12' ).Value := IntToStr( Integer( YearOf( zxDateKsieg.Date ) ) );
aqZapisz.Parameters.ParamByName( 'p13' ).Value := RoundTo( ( StrToFloat( edtWartosc.Text ) / listazaznprojektow.Count ), -2 );
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.Parameters.ParamByName( 'p2' ).Value := TS2[i];
aqZapisz.ExecSQL;
end;
aqZapisz.Connection.Commit;
except
aqZapisz.Connection.Rollback;
raise;
end;
如果值得实施,您应该测量应用程序和服务器任务获取提示所需的时间(2.)。
对于这种情况,较新的Delphi版本有一个方便的System.Diagnostics.TStopWatch
。
var
LInternal, LServer : TStopWatch;
begin
LServer := TStopWatch.Create;
LInternal := TStopWatch.StartNew;
...
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.Parameters.ParamByName( 'p2' ).Value := TS2[i];
LServer.Start;
aqZapisz.ExecSQL;
LServer.Stop;
end;
...
LInternal.Stop;
ShowMessage(
Format(
'Total: %dms Server: %dms',
[ LInternal.ElapsedMilliseconds, LServer.ElapsedMilliseconds ] ) );
end;
答案 2 :(得分:0)
最大的打击是你一个接一个地做多个SQL语句。这包括调用服务器,等待响应以及随之而来的所有额外流量。你有几个选择:
1)您可以尝试依次添加所有sql语句,然后在最后执行一个execsql语句。您将需要“作弊”并内联p2参数。如果您选择此路由,则应自行清理该参数以防止SQL注入等问题。您也可以批量生成X记录。
baseSQL1 := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1, '+
baseSQL2 := ', :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13);';
aqZapisz.SQL.Clear;
for i := 0 to TS2.Count - 1 do
begin
aqZapisz.SQL.Add(baseSQL1 + TS2[i] + baseSQL2);
end;
aqZapisz.Parameters.ParamByName('p1').Value := idk;
aqZapisz.Parameters.ParamByName('p3').Value := edtNrDok.Text;
aqZapisz.Parameters.ParamByName('p4').Value := edtPoz.Text;
aqZapisz.Parameters.ParamByName('p5').Value := id_grupy;;
aqZapisz.Parameters.ParamByName('p6').Value := id_rodzaju;
aqZapisz.Parameters.ParamByName('p7').Value := id_typu;
aqZapisz.Parameters.ParamByName('p8').Value :=
DateToStr(zxDateDok.Date);
aqZapisz.Parameters.ParamByName('p9').Value :=
DateToStr(zxDatePlat.Date);
aqZapisz.Parameters.ParamByName('p10').Value :=
DateToStr(zxDateKsieg.Date);
aqZapisz.Parameters.ParamByName('p11').Value :=
IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p12').Value :=
IntToStr(Integer(YearOf(zxDateKsieg.Date)));
aqZapisz.Parameters.ParamByName('p13').Value :=
RoundTo((StrToFloat(edtWartosc.Text) /
listazaznprojektow.Count), -2);
aqZapisz.ExecSQL;
2)您可以创建存储过程并一次性发送所有数据。完全未经测试。
CREATE PROCEDURE (@p1 nvarchar(max), @p2 nvarchar(max), @p3 nvarchar(max), @p4 nvarchar(max), @p5 nvarchar(max), @p6 nvarchar(max), @p7 nvarchar(max), @p8 nvarchar(max), @p9 nvarchar(max), @p10 nvarchar(max), @p11 nvarchar(max), @p12 nvarchar(max), @p13 nvarchar(max))
AS
BEGIN
DECLARE @idx1 INT;
DECLARE @idx2 INT;
SET @idx1=0;
WHILE @idx1 >-1
BEGIN;
SELECT @idx2 = CHARINDEX(CHAR(13),@p2,@idx1);
IF @idx2 > 0
BEGIN;
INSERT INTO projekty_koszty_rozb
(id_kosztu, id_projektu, nr_dokumentu, pozycja, id_grupy, id_rodzaju, id_typu, data_dok, data_pla, data_ksi, mc,rok,kwota)
VALUES(@p1, SUBSTRING(@p2,@idx1,@idx2-@idx1), @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13)
SET @idx1 = @idx2 + 2;
END;
ELSE
BEGIN;
INSERT INTO projekty_koszty_rozb
(id_kosztu, id_projektu, nr_dokumentu, pozycja, id_grupy, id_rodzaju, id_typu, data_dok, data_pla, data_ksi, mc,rok,kwota)
VALUES(@p1, SUBSTRING(@p2,@idx1,LEN(@p2)+1-@idx1), @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13)
SET @idx1 = -1;
END;
END;
END;
调用该过程并将p2stringlist传递为@ p2:
for i := 0 to TS2.Count - 1 do
begin
p2stringlist.Add(TS2[i]);
end;
答案 3 :(得分:0)
您使用的是哪个版本的Delphi?您的数据库位于何处(WAN或LAN)? 如果你有像XE4-XE7这样的新版本,你可以尝试使用FireDAC FDQuery 它的Array DML功能(使用一组参数提交单个DBMS命令。)。
您的代码如下所示:
with FDQuery1 do begin
SQL.Text := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
// Set up parameter types
Params[0].DataType := ftInteger;
Params[1].DataType := ftString;
Params[1].Size := 40;
Params[2].DataType := ftString;
Params[2].Size := 40;
Params[3].DataType := ftString;
Params[3].Size := 40;
Params[4].DataType := ftString;
Params[4].Size := 40;
Params[5].DataType := ftInteger;
Params[6].DataType := ftInteger;
Params[7].DataType := ftInteger;
Params[8].DataType := ftString;
Params[8].Size := 40;
Params[9].DataType := ftString;
Params[9].Size := 40;
Params[10].DataType := ftString;
Params[10].Size := 40;
Params[11].DataType := ftString;
Params[11].Size := 40;
Params[12].DataType := ftString;
Params[12].Size := 40;
Params[12].DataType := ftFloat;
// Set up parameters' array size
Params.ArraySize := TS2.Count;
// Set parameter values
for i := 0 to TS2.Count - 1 do begin
Params[0].AsIntegers[i] := idk;
Params[1].AsStrings[i] := TS2[i];
Params[2].AsStrings[i] := edtNrDok.Text;
Params[3].AsStrings[i] := edtPoz.Text;
Params[4].AsIntegers[i] := id_grupy;
Params[5].AsIntegers[i] := id_rodzaju;
Params[6].AsIntegers[i] := id_typu;
Params[7].AsStrings[i] := DateToStr(zxDateDok.Date);
Params[8].AsStrings[i] := DateToStr(zxDatePlat.Date);
Params[9].AsStrings[i] := DateToStr(zxDateKsieg.Date);
Params[10].AsStrings[i] := IntToStr(Integer(MonthOf(zxDateKsieg.Date)));
Params[11].AsStrings[i] := IntToStr(Integer(YearOf(zxDateKsieg.Date)));
Params[11].AsDouble[i] := RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2);
end;
// Execute batch
Execute(TS2.Count, 0);
end;
您还可以尝试RemoteSQL,这会更快,并处理潜在网络上的慢性能。 您的基本代码可能如下所示:
procedure AddParams(aServerSQLParams: TRemoteSerializableSQLParams; aParamName: string; aFieldType: TFieldType; aValue: Variant);
var
MyParam: TRemoteSerializableSQLParam;
begin
MyParam := TRemoteSerializableSQLParam(aServerSQLParams.AddParameter);
MyParam.Name := aParamName;
MyParam.DataType := aFieldType;
MyParam.Value := aValue;
end;
procedure SaveMyData;
var
MySerSQLParams: TRemoteSerializableSQLParams;
begin
try
RemoteSQL_Handler1.StartTransaction;
MySerSQLParams:= TRemoteSerializableSQLParams.Create;
for i := 0 to TS2.Count - 1 do begin
MySQL := 'INSERT INTO projekty_koszty_rozb ' +
'(id_kosztu,id_projektu, nr_dokumentu, pozycja,id_grupy, id_rodzaju, id_typu, data_dok, '
+ 'data_pla, data_ksi,mc,rok,kwota) ' +
'VALUES(:p1,:p2, :p3, :p4, :p5, :p6, :p7, :p8, :p9,:p10,:p11,:p12,:p13)';
AddParams(MySerSQLParams, 'p1', ftInteger, idk);
AddParams(MySerSQLParams, 'p2', ftString, TS2[i]);
AddParams(MySerSQLParams, 'p3', ftString, edtNrDok.Text);
AddParams(MySerSQLParams, 'p4', ftString, edtPoz.Text);
AddParams(MySerSQLParams, 'p5', ftInteger, id_grupy);
AddParams(MySerSQLParams, 'p6', ftInteger, id_rodzaju);
AddParams(MySerSQLParams, 'p7', ftInteger, id_typu);
AddParams(MySerSQLParams, 'p8', ftString, DateToStr(zxDateDok.Date));
AddParams(MySerSQLParams, 'p9', ftString, DateToStr(zxDatePlat.Date));
AddParams(MySerSQLParams, 'p10', ftString, DateToStr(zxDateKsieg.Date));
AddParams(MySerSQLParams, 'p11', ftString, IntToStr(Integer(MonthOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p12', ftString, IntToStr(Integer(YearOf(zxDateKsieg.Date))));
AddParams(MySerSQLParams, 'p13', ftFloat, RoundTo((StrToFloat(edtWartosc.Text) / listazaznprojektow.Count), -2));
RemoteSQL_Handler1.ExecuteSQL(MySQL, MySerSQLParams);
end;
RemoteSQL_Handler1.CommitTransaction;
except
RemoteSQL_Handler1.RollBackTransaction;
FreeAndNil(MySerSQLParams);
end;
FreeAndNil(MySerSQLParams);
end;
RemoteSQL收集您的查询,压缩它们并立即将它们发送到服务器端(批处理)。