Обратите внимание на правку ниже, чтобы получить дополнительную информацию и возможное решение
Недавно мы изменили большое приложение Delphi, чтобы использовать соединения и запросы ADO вместо соединений и запросов BDE. После этого изменения производительность стала ужасной.
Я профилировал приложение, и, похоже, узкое место связано с фактическим вызовом TADOQuery.Open
. Другими словами, я мало что могу сделать с точки зрения кода, чтобы улучшить это, кроме реструктуризации приложения, чтобы фактически меньше использовать базу данных.
Есть ли у кого-нибудь предложения о том, как улучшить производительность приложения Delphi, подключенного к ADO? Я пробовал оба предложения , приведенных здесь, практически безрезультатно.
Чтобы понять разницу в производительности, я протестировал ту же большую операцию:
Под BDE: 11 секунд
Под ADO: 73 секунды
В соответствии с ADO после изменений, упомянутых в этой статье: 72 секунды.
Мы используем серверную часть Oracle в среде клиент-сервер. Каждый локальный компьютер поддерживает отдельное соединение с базой данных.
Для записи строка подключения выглядит так:
const
c_ADOConnString = 'Provider=OraOLEDB.Oracle.1;Persist Security Info=True;' +
'Extended Properties="plsqlrset=1";' +
'Data Source=DATABASE.DOMAIN.COM;OPTION=35;' +
'User ID=******;Password=*******';
Чтобы ответить на вопросы, заданные зендаром:
Я использую Delphi 2007 в Windows Vista и XP.
Серверная часть - это база данных Oracle 10g.
Как указано в строке подключения, мы используем драйвер OraOLEDB.
Версия MDAC на моем тестовом компьютере - 6.0.
Изменить:
Под BDE у нас было много кода, который выглядел так:
procedure MyBDEProc;
var
qry: TQuery;
begin
//fast under BDE, but slow under ADO!!
qry := TQuery.Create(Self);
try
with qry do begin
Database := g_Database;
Sql.Clear;
Sql.Add('SELECT');
Sql.Add(' FIELD1');
Sql.Add(' ,FIELD2');
Sql.Add(' ,FIELD3');
Sql.Add('FROM');
Sql.Add(' TABLE1');
Sql.Add('WHERE SOME_FIELD = SOME_CONDITION');
Open;
//do something
Close;
end; //with
finally
FreeAndNil(qry);
end; //try-finally
end; //proc
Но мы обнаружили, что вызов Sql.Add
на самом деле очень затратный в ADO, потому что событие QueryChanged
запускается каждый раз, когда вы меняете CommandText
. Так что замена вышеперечисленного на это была НАМНОГО быстрее:
procedure MyADOProc;
var
qry: TADOQuery;
begin
//fast(er) under ADO
qry := TADOQuery.Create(Self);
try
with qry do begin
Connection := g_Connection;
Sql.Text := ' SELECT ';
+ ' FIELD1 '
+ ' ,FIELD2 '
+ ' ,FIELD3 '
+ ' FROM '
+ ' TABLE1 '
+ ' WHERE SOME_FIELD = SOME_CONDITION ';
Open;
//do something
Close;
end; //with
finally
FreeAndNil(qry);
end; //try-finally
end; //proc
Еще лучше, вы можете скопировать TADOQuery
из ADODB.pas, переименовать его под новым именем и удалить событие QueryChanged
, которое, насколько я могу судить, вообще не делает ничего полезного. Затем используйте новую, измененную версию TADOQuery вместо собственной.
type
TADOQueryTurbo = class(TCustomADODataSet)
private
//
protected
procedure QueryChanged(Sender: TObject);
public
FSQL: TWideStrings;
FRowsAffected: Integer;
function GetSQL: TWideStrings;
procedure SetSQL(const Value: TWideStrings);
procedure Open;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function ExecSQL: Integer; {for TQuery compatibility}
property RowsAffected: Integer read FRowsAffected;
published
property CommandTimeout;
property DataSource;
property EnableBCD;
property ParamCheck;
property Parameters;
property Prepared;
property SQL: TWideStrings read FSQL write SetSQL;
end;
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
constructor TADOQueryTurbo.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FSQL := TWideStringList.Create;
TWideStringList(FSQL).OnChange := QueryChanged;
Command.CommandText := 'SQL'; { Do not localize }
end;
destructor TADOQueryTurbo.Destroy;
begin
inherited;
inherited Destroy;
FreeAndNil(FSQL);
end;
function TADOQueryTurbo.ExecSQL: Integer;
begin
CommandText := FSQL.Text;
inherited;
end;
function TADOQueryTurbo.GetSQL: TWideStrings;
begin
Result := FSQL;
end;
procedure TADOQueryTurbo.Open;
begin
CommandText := FSQL.Text;
inherited Open;
end;
procedure TADOQueryTurbo.QueryChanged(Sender: TObject);
begin
// if not (csLoading in ComponentState) then
// Close;
// CommandText := FSQL.Text;
end;
procedure TADOQueryTurbo.SetSQL(const Value: TWideStrings);
begin
FSQL.Assign(Value);
CommandText := FSQL.Text;
end;