I have been experimenting with retrieving data from an MSSQL server from a Delphi program (using Delphi 2007). The program has so far been using TADODataset to retrieve data. During tests we found that TQuery with an ODBC provider fetched a large select of data much quicker. But on the other hand TADODataset preformed much better with parametrized+prepared selects. Both TADODataset and TQuery connect to the same MSSQL database table. For this experiment I used MSSQL Native Client as provider for both. TADODataset is set up with a connection string to the database, TQuery uses TDatabase with ODBC connection.
Here is some code from the experiment:
procedure TForm2.Button1Click(Sender: TObject);
begin
ADODataSet1.CommandText := 'select top 100000 '+FDataFields+' from transactions';
GetData(ADODataSet1);
ReadData(ADODataset1);
ADODataSet1.Close;
end;
procedure TForm2.Button2Click(Sender: TObject);
var
I: Integer;
begin
ADODataSet1.CommandText := 'select '+FDataFields+' from transactions where originaltransno = :FieldValue order by Key2';
ADODataSet1.Parameters[0].Value := '000';
ADODataSet1.Prepared := True;
GetData(ADODataSet1);
for I := 0 to 2000 do
begin
ADODataSet1.Parameters[0].Value := '123';
//no match in DB, just a check if it is there
ADODataSet1.Requery;
ReadData(ADODataset1);
end;
ADODataSet1.Close;
ADODataSet1.Prepared := False;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
Query1.SQL.Clear;
Query1.SQL.Add('select top 100000 '+FDataFields+' from transactions');
GetData(Query1);
ReadData(Query1);
Query1.Close;
end;
procedure TForm2.Button4Click(Sender: TObject);
var
I: Integer;
begin
Query1.SQL.Clear;
Query1.SQL.Add('select '+FDataFields+' from transactions where originaltransno = :FieldValue order by Key2');
Query1.Params[0].Value := '000';
Query1.Prepare;
GetData(Query1);
for I := 0 to 2000 do
begin
Query1.Params[0].Value := '123';
Query1.Close;
Query1.Open;
ReadData(Query1);
end;
Query1.Close;
Query1.UnPrepare;
end;
procedure TForm2.GetData(ADataSet: TDataSet);
begin
ADataSet.DisableControls;
ADataSet.Open;
end;
procedure TForm2.ReadData(ADataSet: TDataSet);
begin
while not ADataSet.EOF do
begin
ReadLine(ADataSet);
ADataSet.Next;
end;
end;
function TForm2.ReadLine(ADataSet: TDataSet): string;
var
I: Integer;
begin
for I := 0 to ADataSet.Fields.Count - 1 do
begin
if ADataSet.FieldDefs[I].DataType = ftString then
Result := Result + ADataSet.Fields[I].AsString;
end;
end;
A rough timing (using CPU Time in task manager)
- Button1 - TADODataset large select: 13 seconds
- Button2 - TADODataset small selects: 7 seconds
- Button3 - TQuery large select: 4 seconds
- Button4 - TQuery small selects: 24 seconds
Futher testing indicated the slow time with large TADODataset select is from reading the fields AsString I tried replacing ReadLine:
function TForm2.ReadLine(ADataSet: TDataSet): int64;
var
I: Integer;
begin
for I := 0 to ADataSet.Fields.Count - 1 do
begin
if ADataSet.FieldDefs[I].DataType = ftInteger then
Result := Result + ADataSet.Fields[I].AsInteger;
end;
end;
With integer reading I got these timings:
- Button1 - TADODataset large select: 3 seconds
- Button3 - TQuery large select: 3 seconds
I tried using Value instead, but "adding" a Variant to string was much slower
Can I do anything in reading the strings that speed up TADODataset reading?