Jos*_*ons 13 delphi oracle performance ado bde
请注意下面的编辑以获取更多信息,以及可能的解决方案
我们最近修改了一个大型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=*******';
Run Code Online (Sandbox Code Playgroud)
回答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
Run Code Online (Sandbox Code Playgroud)
但我们发现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
Run Code Online (Sandbox Code Playgroud)
更好的是,您可以复制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;
Run Code Online (Sandbox Code Playgroud)
zen*_*dar 14
我不知道Delphi 2007,但我对Delphi 7和Oracle 8做了同样的事情.
这是我做的事情:
几年前我发现了 ADOExpress 的性能问题:
注意:在 ADO 成为 Delphi 的标准部分之前,Borland 将其作为名为ADOExpress的插件出售。它只是 Microsoft 的 ActiveX 数据对象 (ADO) COM 对象的对象包装器。
我测试了三个场景
.DisableControls在TADOQuery之前调用Open我发现
Query.DisableControls使每次调用.Next速度提高 50 倍Query.Recordset.Fields.Items['columnName'].Value而不是Query.FieldByName('columnName')使每个值查找速度提高 2.7 倍使用TADODataSet(verses TADOQuery) 没有区别
Loop Results Get Values
ADOExpress: 28.0s 46.6s
ADOExpress w/DisableControls: 0.5s 17.0s
ADO (direct use of interfaces): 0.2s 4.7s
Run Code Online (Sandbox Code Playgroud)注意:这些值用于循环 20,881 行,并查找 21 列的值。
基线错误代码:
var
qry: TADOQuery;
begin
qry := TADOQuery.Create(nil);
try
qry.SQL.Add(CommandText);
qry.Open;
while not qry.EOF do
begin
...
qry.Next;
end;
Run Code Online (Sandbox Code Playgroud)
使用 DisableControls 使循环速度提高 5000%:
var
qry: TADOQuery;
begin
qry := TADOQuery.Create(nil);
try
qry.DisableControls;
qry.SQL.Add(CommandText);
qry.Open;
while not qry.EOF do
begin
...
qry.Next;
end;
Run Code Online (Sandbox Code Playgroud)
使用 Fields 集合使值查找速度提高 270%:
var
qry: TADOQuery;
begin
qry := TADOQuery.Create(nil);
try
qry.DisableControls;
qry.SQL.Add(CommandText);
qry.Open;
while not qry.EOF do
begin
value1 := VarAsString(qry.Recordset.Fields['FieldOne'].Value);
value2 := VarAsInt(qry.Recordset.Fields['FieldTwo'].Value);
value3 := VarAsInt64(qry.Recordset.Fields['FieldTwo'].Value);
value4 := VarAsFloat(qry.Recordset.Fields['FieldThree'].Value);
value5 := VarAsWideString(qry.Recordset.Fields['FieldFour'].Value);
...
value56 := VarAsMoney(qry.Recordset.Fields['FieldFive'].Value);
qry.Next;
end;
Run Code Online (Sandbox Code Playgroud)
由于这是一个足够常见的问题,我们创建了一个辅助方法来解决这个问题:
class function TADOHelper.Execute(const Connection: TADOConnection;
const CommandText: WideString): TADOQuery;
var
rs: _Recordset;
query: TADOQuery;
nRecords: OleVariant;
begin
Query := TADOQuery.Create(nil);
Query.DisableControls; //speeds up Query.Next by a magnitude
Query.Connection := Connection;
Query.SQL.Text := CommandText;
try
Query.Open();
except
on E:Exception do
begin
Query.Free;
raise;
end;
end;
Result := Query;
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
13655 次 |
| 最近记录: |