有趣的问题。
更新请参阅下面的更新。
我在我的 SS2014 Sql Server 上设置了一些测试数据,以使用如下代码运行一些测试:
ID := 1;
for Line := 1 to 1000 do begin
for AHour := 1 to 24 do begin
for AMinute := 1 to 60 do begin
AdoQuery1.InsertRecord([ID, Line, AHour, AMinute]);
Inc(ID);
end;
end;
end;
end;
然后,我进行了一些类似这样的测试
procedure TForm1.LocateTest1(DisableControls, UseSort : Boolean);
var
T1 : Integer;
Line,
AHour,
AMinute : Integer;
begin
AdoQuery1.Sql.Text := 'select * from linetest order by line, ahour, aminute';
AdoQuery1.CursorLocation := clUseClient;
AdoQuery1.Open;
T1 := GettickCount;
if DisableControls then
AdoQuery1.DisableControls;
if UseSort then
AdoQuery1.Recordset.Sort := 'Line,AHour,AMinute';
Line := 1000;
AHour := 23;
for AMinute := 60 downto 1 do begin
if not AdoQuery1.Locate('Line;AHour;AMinute', VarArrayOf([Line, AHour, AMinute]), []) then
Caption := Format('Locate failed %d %d %d', [Line, AHour, AMinute]);
end;
Memo1.Lines.Add('Test1 : ' + IntToStr(GetTickCount - T1));
if DisableControls then
AdoQuery1.EnableControls;
AdoQuery1.Close;
end;
涉及Disable/EnableControls的原因是因为我报告的结果
这里Why does scrolling through ADOTable get slower and slower?
,即使没有 db-aware,调用 DisableControls 也会对滚动速度产生巨大影响
涉及的控制。
但是,滚动似乎不会对在 TAdoQuery 上执行 Locate() 产生重大影响,因为调用 DisableControls 只花费了大约 1.5 秒的记录时间
26 秒。显然,TAdoQuery.Locate 在处理大量行时表现不佳。
UseSort 参数的想法是查看是否将 RecordSet 排序在
AdoQuery 对速度有任何影响,但没有,原因是 Locate 调用
无论如何都使用排序的 TCustomAdoDataSet.LocateRecord。
您提到了添加索引。不幸的是,TAdoQuery 只支持使用服务器端索引
在执行 thq SQL 查询时,未在检索到的结果集中定位记录。您可以添加
TAdoTable 的客户端索引,但根据与上述类似的测试,令我惊讶的是,
他们做了
与 Locate() 的速度几乎没有区别。
所以,鉴于我目前的结果,使用参数化的方法似乎更快
SELECT 仅检索当前感兴趣的行,而不是尝试定位它
在一个大的测试集中。 Alterantaivel,您可以通过 DatasetProvider 或 FireDAC FDMemTable 等将结果集检索到 ClientDataSer 中。Ymmv,这取决于您正在做什么...
更新自从发布我的原始答案以来,我还有一些进一步的更新
包括它可能是有用的。
一种方法是使用调用 AdoQuery 的 RecordSet 的 Find 和 Filter 方法来模拟 Locate 的方法,该方法比重复执行 AdoQuery1.Locate 快得多(大约 15 秒)。我仍在对此进行调查,并将在一两天内发布另一个更新。
另一个是简单地提到做定位是做 FireDAC FDQuery 而不是 AdoQuery。使用以下代码,这似乎与 AdoQuery 在 9 秒内执行相同的定位集需要大约 25 秒:
使用 FDQuery.Locate
procedure TForm2.LocateTest;
var
T1 : Integer;
Line,
AHour,
AMinute : Integer;
begin
FDQuery1.Sql.Text := 'select * from linetest order by line, ahour desc, aminute desc';
//FDQuery1.CursorLocation := clUseClient;
FDQuery1.CursorKind := ckForwardOnly;
FDQuery1.Open;
T1 := GettickCount;
Line := 1000;
AHour := 1;
for AMinute := 1 to 60 do begin
if not FDQuery1.Locate('Line;AHour;AMinute', VarArrayOf([Line, AHour, AMinute]), []) then
Caption := Format('Locate failed %d %d %d', [Line, AHour, AMinute]);
end;
Memo1.Lines.Add('Test1 : ' + IntToStr(GetTickCount - T1));
FDQuery1.Close;
end;