Обратите внимание на приведенное ниже описание для получения более подробной информации и возможного решения
Недавно мы модифицировали большое приложение 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=*******';
Чтобы ответить на вопросы, заданные zendar:
Я использую 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;