интересно q.
Обновление см. Обновление ниже.
Я настроил некоторые тестовые данные на моем сервере SS2014 Sql для запуска некоторых тестов, используя такой код:
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 была из-за результатов, о которых я сообщил здесь Почему прокрутка через ADOTable становится медленнее и медленнее ? , что вызов DisableControls оказывает огромное влияние на скорость прокрутки, даже если не задействованы элементы управления с поддержкой db.
Однако кажется, что прокрутка не оказывает существенного влияния на выполнение Locate () в TAdoQuery, потому что вызов DisableControls занял всего около 1,5 секунд из записанного времени около 26 секунд. Очевидно, что TAdoQuery.Locate не очень хорошо работает с большим количеством строк.
Идея параметра UseSort заключалась в том, чтобы выяснить, имеет ли сортировка RecordSet за AdoQuery какое-то влияние на скорость, но это нет, причина в том, что Locate вызывает TCustomAdoDataSet.LocateRecord, который все равно использует Sort.
Вы упомянули добавление индексов. К сожалению, TAdoQuery поддерживает только использование серверных индексов при выполнении запроса thq SQL, но не находит записи в полученном наборе результатов. Вы можете добавлять клиентские индексы в TAdoTable, но, согласно моему тесту, похожему на приведенный выше, к моему удивлению, они практически не влияют на скорость Locate ().
Таким образом, учитывая мои результаты, было бы гораздо проще использовать параметризованный SELECT для извлечения только интересующей строки, а не пытаться найти ее в большом наборе результатов. Alterantaivel, вы можете получить набор результатов в ClientDataSer через DatasetProvider или в FireDA C FDMemTable, et c. Гм, это зависит от того, что вы делаете в точности ...
Обновление После публикации моего исходного ответа у меня есть пара дополнительных обновлений, которые, возможно, было бы полезно включить.
Один из них касается способа имитации Locate с использованием вызовов методов поиска и фильтрации RecordSet в AdoQuery, который значительно быстрее (около 15 секунд), чем повторное выполнение AdoQuery1.Locate. Я все еще пробую это и опубликую другое обновление через день или два.
Другой - кратко упомянуть, что Locates делает FireDA C FDQuery вместо AdoQuery. Это похоже на тот же набор Locates, который занимает около 25 секунд с AdoQuery менее чем за 9 секунд, используя следующий код:
Используя 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;