Пожалуйста, обратите внимание на редактирование ниже для получения дополнительной информации и возможного решения
Недавно мы изменили большое приложение Delphi для использования соединений и запросов ADO вместо соединений и запросов BDE. После этого изменения производительность стала ужасной.
Я профилировал приложение, и узкое место, кажется, при фактическом вызове TADOQuery.Open
. Другими словами, я мало что могу сделать с точки зрения кода, чтобы улучшить это, кроме реструктуризации приложения, чтобы фактически использовать базу данных меньше.
У кого-нибудь есть предложения по улучшению производительности приложения Delphi, подключенного к ADO? Я попробовал оба предложения, приведенные здесь , практически безрезультатно.
Чтобы дать представление о разнице в производительности, я протестировал ту же самую большую операцию:
Мы используем серверную часть 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.
Edit:
Под 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;