Ich kann Ihre Ergebnisse mit einer AdoQuery mit einem MS Sql Server-Dataset ähnlicher Größe wie Ihres reproduzieren.
Nachdem ich ein bisschen Linienprofilierung gemacht habe, denke ich, dass ich die Antwort darauf gefunden habe, und es ist etwas kontraintuitiv. Ich bin sicher, dass jeder, der DB-Programmierung in Delphi macht, daran interessiert ist, dass das Durchlaufen eines Datensatzes viel schneller ist, wenn Sie die Schleife durch Aufrufe von Disable/EnableControls umgeben. Aber wer würde das tun, wenn keine datenbanksensitiven Steuerelemente an den Datensatz angehängt sind?
Nun, es stellt sich heraus, dass in Ihrer Situation, obwohl es keine DB-fähigen Steuerelemente gibt, die Geschwindigkeit enorm steigt, wenn Sie Disable/EnableControls unabhängig verwenden.
Der Grund dafür ist, dass TCustomADODataSet.InternalGetRecord in AdoDB.Pas diese enthält:
if ControlsDisabled then
RecordNumber := -2 else
RecordNumber := Recordset.AbsolutePosition;
und nach meiner Linie Profiler, die während nicht AdoQuery1.Next Schleife verbringt 98,8% seiner Zeit AdoQuery1.Eof zu tun Ausführung die Zuordnung
RecordNumber := Recordset.AbsolutePosition;
! Die Berechnung von Recordset.AbsolutePosition ist natürlich auf der "falschen Seite" der Recordset-Schnittstelle versteckt, aber die Tatsache, dass die Zeit, um sie aufzurufen, scheinbar zunimmt, je weiter Sie in das Recordset gehen, macht es vernünftig zu spekulieren, dass es berechnet wird indem Sie vom Anfang der Daten des Datensatzes aus zählen.
Natürlich ControlsDisabled
gibt true zurück, wenn DisableControls
wurde durch einen Aufruf EnableControls
genannt und kann nicht rückgängig gemacht. Also, wiederhole es mit der Schleife, die von Disable/EnableControls umgeben ist, und hoffentlich bekommst du ein ähnliches Ergebnis wie meins. Es sieht so aus, als hätten Sie Recht, dass die Verlangsamung nicht mit Speicherzuweisungen zusammenhängt.
Verwendung des folgenden Codes:
procedure TForm1.btnLoopClick(Sender: TObject);
var
I: Integer;
T: Integer;
Step : Integer;
begin
Memo1.Lines.BeginUpdate;
I := 0;
Step := 4000;
if cbDisableControls.Checked then
AdoQuery1.DisableControls;
T := GetTickCount;
{.$define UseRecordSet}
{$ifdef UseRecordSet}
while not AdoQuery1.Recordset.Eof do begin
AdoQuery1.Recordset.MoveNext;
Inc(I);
if I mod Step = 0 then begin
T := GetTickCount - T;
Memo1.Lines.Add(IntToStr(I) + ':' + IntToStr(T));
T := GetTickCount;
end;
end;
{$else}
while not AdoQuery1.Eof do begin
AdoQuery1.Next;
Inc(I);
if I mod Step = 0 then begin
T := GetTickCount - T;
Memo1.Lines.Add(IntToStr(I) + ':' + IntToStr(T));
T := GetTickCount;
end;
end;
{$endif}
if cbDisableControls.Checked then
AdoQuery1.EnableControls;
Memo1.Lines.EndUpdate;
end;
ich die folgenden Ergebnisse erhalten (mit DisableControls nicht außer genannt, wo angegeben):
Using CursorLocation = clUseClient
AdoQuery.Next AdoQuery.RecordSet AdoQuery.Next
.MoveNext + DisableControls
4000:157 4000:16 4000:15
8000:453 8000:16 8000:15
12000:687 12000:0 12000:32
16000:969 16000:15 16000:31
20000:1250 20000:16 20000:31
24000:1500 24000:0 24000:16
28000:1703 28000:15 28000:31
32000:1891 32000:16 32000:31
36000:2187 36000:16 36000:16
40000:2438 40000:0 40000:15
44000:2703 44000:15 44000:31
48000:3203 48000:16 48000:32
=======================================
Using CursorLocation = clUseServer
AdoQuery.Next AdoQuery.RecordSet AdoQuery.Next
.MoveNext + DisableControls
4000:1031 4000:454 4000:563
8000:1016 8000:468 8000:562
12000:1047 12000:469 12000:500
16000:1234 16000:484 16000:532
20000:1047 20000:454 20000:546
24000:1063 24000:484 24000:547
28000:984 28000:531 28000:563
32000:906 32000:485 32000:500
36000:1016 36000:531 36000:578
40000:1000 40000:547 40000:500
44000:968 44000:406 44000:562
48000:1016 48000:375 48000:547
Aufruf AdoQuery1.Recordset.MoveNext
Anrufe direkt in die MDac/ADO-Schicht von natürlich, während AdoQuery1.Next den gesamten Overhead des Standardmodells TDataSet umfasst. Wie Serge Kraikov sagte, macht die Änderung der CursorLocation einen Unterschied und zeigt nicht die Verlangsamung, die wir beobachtet haben, obwohl sie offensichtlich wesentlich langsamer ist als clUseClient zu verwenden und DisableControls aufzurufen. Ich nehme an, es hängt genau davon ab, was Sie versuchen zu tun, ob Sie die zusätzliche Geschwindigkeit der Verwendung von clUseClient mit RecordSet.MoveNext nutzen können.
Nein. Ich erstelle die Steuerung programmgesteuert, es gibt nichts mehr als das, was Sie im Beispielcode sehen können. – saastn
Ist die For-Schleife nicht um eins deaktiviert? Wie auch immer, sind Sie überrascht, dass wenn Sie viele Datensätze lesen, es eine Menge Speicherzuweisungen erfordert und dass diese länger dauern, je mehr Speicher zugewiesen wird? – MartynA
@MartynA Sie haben Recht mit der Schleife. Aber ich kann nicht sagen, dass es Speicherzuweisung ist, die es langsamer macht. Scheint, als ob es alle Datensätze in 'Table.Open 'abruft, Task-Manager zeigt nach dem Ausführen dieser Zeile keine Speicherzuweisung an. – saastn