请注意下面的编辑以获取更多信息以及可能的解决方案
我们最近修改了一个大型 Delphi 应用程序以使用 ADO 连接和查询而不是 BDE 连接和查询。自那次改变以来,性能变得很糟糕。
我已经分析了应用程序,瓶颈似乎在实际调用TADOQuery.Open
. 换句话说,从代码的角度来看,除了重构应用程序以减少对数据库的使用之外,我无能为力。
有人对如何提高与 ADO 连接的 Delphi 应用程序的性能有任何建议吗?我已经尝试了这里给出的两个建议,几乎没有影响。
为了了解性能差异,我对相同的大型操作进行了基准测试:
在 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 提出的问题:
我在 Windows Vista 和 XP 上使用 Delphi 2007。
后端是一个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;