![]() |
Datenbank: SQLITE • Version: 3 • Zugriff über: Zeos
Kleiner Geschwindigkeitstest von Insert
Hallo,
mich hat es interessiert, wie sich die Geschwindigkeiten von Inserts bei SQLite3 und Zeos verändern, mit unterschiedlichen "schreibweisen"; Und habe festgestellt, dass es durchaus erhebliche Unterschiede geben kann. Ich habe den Test mehrmals durchlaufen, auch mit unterschiedlichen Zahlen und habe folgende Durchschnittszeiten bekommen: Hier die sortierte Ergebnisse:
Code:
Benötigte Zeit % Funktionsname
1,20 % Test4 (Insert; in Transaction, außerhalb der Funktion) 1,21 % Test3 (Insert; in Transaction innerhalb der Funktion) 97,58 % TEst1 (Insert und exec... direkt hintereinander) (Funktion 2 hat im Test nicht teilgenommen. Ich war der Annahme, es ist auch mögliche mehrere Inserts mit add zu schreiben, doch das ist so nicht möglich.) Hier die verschiedene Abschnitte: Derzeit aktuelle Tabelle im Beitrag: ![]()
Delphi-Quellcode:
function test1(testzahl:integer): string;
var a: integer; begin for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl)'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; function test2(testzahl:integer): string; var a: integer; begin Form1.ZQuery1.SQL.Clear; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.add('Insert into daten2 (zahl) values (:zahl);'); Form1.ZQuery1.ParamByName('zahl').AsInteger := a; end; Form1.ZQuery1.ExecSQL; end; function test3(testzahl:integer): string; var a: integer; begin Form1.ZQuery1.SQL.text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := ''; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; Form1.ZQuery1.SQL.text := 'Commit;'; Form1.ZQuery1.ExecSQL; end; function test4(testzahl:integer): string; var a: integer; begin Form1.ZQuery1.SQL.Text := ''; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; //START der Funktionen: Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test1(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test3(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; test4(testzahl); Form1.ZQuery1.SQL.text := 'Commit;'; Form1.ZQuery1.ExecSQL; LG Monda< |
AW: Kleiner Geschwindigkeitstest von Insert
Funktioniert test2, wenn Du die Funktion dahingehend änderst?
Delphi-Quellcode:
function test2(testzahl:integer): string;
var a: integer; begin Form1.ZQuery1.SQL.Clear; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.add(Format('Insert into daten2 (zahl) values (%d);',[a])); end; Form1.ZQuery1.ExecSQL; end; |
AW: Kleiner Geschwindigkeitstest von Insert
wenn es dir echt um Geschwindigkeit geht, dann sind deine Insert Schleifen noch subobtimal
entweder einfach
Delphi-Quellcode:
oder besser
for a := 1 to testzahl do begin
Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values ('+IntToStr(a)+')'; Form1.ZQuery1.ExecSQL; end;
Delphi-Quellcode:
Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);';
qPara:=Form1.ZQuery1.ParamByName('zahl'); for a := 1 to testzahl do begin qPara.AsInteger := a; Form1.ZQuery1.ExecSQL; end; ich würde wenn es was wie "PrepareSQL" bei Zeos gibt es nutzen, und Parameter nur 1xabfragen+"merken", sowie Query als Übergabe im Aufruf mitgeben(Form. ist immer unschön):
Delphi-Quellcode:
Query.SQL.text := 'begin transaction;';
Query.ExecSQL; Query.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Query.PrepareSQL; qPara:=Query.ParamByName('zahl'); for a := 1 to testzahl do begin qPara.AsInteger := a; Query.ExecSQL; end; Query.SQL.text := 'Commit;'; Query.ExecSQL; |
AW: Kleiner Geschwindigkeitstest von Insert
Hallo,
vermutlich bekommst Du andere Ergebnisse, wenn Du die Reihenfolge der Tests veränderst. Ich weiß nicht, wie SQLLITE das intern umsetzt, aber nach einem Commit des DELETE-Statements können in der Regel die selben Speicherbereiche für die neuen Inserts genutzt werden, andernfalls müssen Dateien vergrößert werden oder neue Blöcke vom OS angefordert werden, um die Datensätze unterzubringen. Das gilt insbesondere im Singleuser Betrieb. Gruß Björn |
AW: Kleiner Geschwindigkeitstest von Insert
Hey Super für eure Anregungen!
@bnreimer42 Bzgl. der Reihenfolge der Tests: Ich habe die Reihenfolge geändert, und die Ergebnisse blieben die gleichen. @nahpets Ja Funktion 2 funktioniert mit deinem Vorschlag tatsächlich. @mensch72 Gibt es Vor- Nachteile von .ParamByName()...? Ich habe mir einst angewöhnt so zu schreiben und nicht mehr direkt in die Zeile, weil es einen schwerwiegenden Grund hatte. Leider weiß ich nicht mehr was der Grund dafür war. Nun nochmal mit den neuen Ergebnissen, im Vergleich:
Code:
Benötigte Zeit % | Funktionsname
48,57 Test2 (Insert mit .add(Format(... siehe auch Test5 ) 17,62 Test1 (Insert und exec... direkt hintereinander) 16,88 Test8 (Wie Test7 + Prepare) 16,46 Test7 (Nur ParamByName in Schleife) 0,22 Test4 (Insert; in Transaction, außerhalb der Schleife) 0,21 Test3 (Insert; in Transaction, innerhalb der Funktion) 0,03 Test9 (wie 8 + Transaction) 0,01 Test6 (Wie Test5 mit Transaction) 0,01 Test5 (Direkt, Ohne .ParamByName.) 17,62 Test1 (Insert und exec... direkt hintereinander) 48,57 Test2 (Insert mit .add(Format(... siehe auch Test5 ) 0,21 Test3 (Insert; in Transaction, innerhalb der Funktion) 0,22 Test4 (Insert; in Transaction, außerhalb der Schleife) 0,01 Test5 (Direkt, Ohne .ParamByName.) 0,01 Test6 (Wie Test5 mit Transaction) 16,46 Test7 (Nur ParamByName in Schleife) 16,88 Test8 (Wie Test7 + Prepare) 0,03 Test9 (wie 8 + Transaction) Und wieder der Code:
Delphi-Quellcode:
function test1(testzahl: integer): string; var a: integer; begin for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl)'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; function test2(testzahl: integer): string; //nahpets var a: integer; begin Form1.ZQuery1.SQL.Clear; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.add(Format('Insert into daten2 (zahl) values (%d);', [a])); end; Form1.ZQuery1.ExecSQL; end; function test3(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := ''; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; end; function test4(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.Text := ''; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; function test5(testzahl: integer): string; //mensch72 var a: integer; begin Form1.ZQuery1.SQL.Clear; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (' + IntToStr(a) + ')'; end; Form1.ZQuery1.ExecSQL; end; function test6(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Clear; for a := 1 to testzahl do begin Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (' + IntToStr(a) + ')'; end; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; end; function test7(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; for a := 1 to testzahl do begin Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; function test8(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.Prepare; for a := 1 to testzahl do begin Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end; function test9(testzahl: integer): string; var a: integer; begin Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.Prepare; for a := 1 to testzahl do begin Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; //Starts.... Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test1(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test2(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test3(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; test4(testzahl); Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test5(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test6(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test7(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test8(testzahl); Form1.ZQuery1.SQL.Text := 'Delete from daten2'; Form1.ZQuery1.ExecSQL; test9(testzahl); |
AW: Kleiner Geschwindigkeitstest von Insert
Hier muss testzahl mal geprüft werden, ob es den Parameter Zahl gibt. Das kostet Rechenzeit.
Delphi-Quellcode:
Hier muss einmal geprüft werden, ob es den Parameter Zahl gibt.
function test7(testzahl: integer): string;
var a: integer; begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; for a := 1 to testzahl do begin Form1.ZQuery1.ParamByName('zahl').AsInteger := a; Form1.ZQuery1.ExecSQL; end; end;
Delphi-Quellcode:
Ergibt das 'nen messbaren Unterschied?
function test7a(testzahl: integer): string;
var a: integer; p: TParam; begin Form1.ZQuery1.SQL.text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.Prepare; p := Form1.ZQuery1.ParamByName('Zahl'); for a := 1 to testzahl do begin p.AsInteger := a; Form1.ZQuery1.ExecSQL; end; end;
Delphi-Quellcode:
Hier eventuell auch?
function test3a(testzahl: integer): string;
var a: integer; p: TParam; begin Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.Prepare; p := Form1.ZQuery1.ParamByName('Zahl'); for a := 1 to testzahl do begin p.AsInteger := a; Form1.ZQuery1.ExecSQL; end; Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; end; |
AW: Kleiner Geschwindigkeitstest von Insert
Ich habe nun verschiedenes getestet und sehe mir die Ergebnisse an:
Test2,1,8,7: Sind deutlich langsam. Sollte man so keinesfalls verwenden, wenn Geschwindigkeit ein Kriterium sein soll. Nur ParamByName in der schleife (Test7) ergibt für sich keinen Geschwindigkeitsvorteil, auch nicht mit Prepare verbunden (Test8); Und ergibt nur Sinn, wenn man diese mit Transaction verbindet (Test9). Mit Format() (Test2) sollte man bzgl. Schnelligkeit eher vorsichtig sein, diese war sogar fast dreimal solangsam wie Test1 (Insert,Exec direkt hintereinander). Test3,4: Insert mit Transactionen gehen bereits erheblich schneller und können/sollten verwendet werden. Dabei spielt es keine Rolle ob "begin transaction / commit) innerhalb der Funktion oder außerhalb ist. Test9,6,5: Sind nochmal um ca. 0,2 % schneller als Test3 und 4. Variablen direkt in die SQL Anweisung zu schreiben (Test5), war das schnellste; Gleiches mit Transaction (Test6) ist sogar einen Tick langsamer und wird nicht wirklich benötigt. |
AW: Kleiner Geschwindigkeitstest von Insert
@nahpets
Ah Ok, ich dachte das macht kein Unterschied. Ich kannte das so noch nicht; Ich werde es testen. |
AW: Kleiner Geschwindigkeitstest von Insert
na wenn jetzt das "Form" noch wegfällt, wären wir bei der Version, welche nach meinem Bauchgefühl am schnellsten und "am saubersten" wäre :)
Delphi-Quellcode:
function test3a(testzahl: integer): string;
var a: integer; p: TParam; begin Form1.ZQuery1.SQL.Text := 'begin transaction;'; Form1.ZQuery1.ExecSQL; Form1.ZQuery1.SQL.Text := 'Insert into daten2 (zahl) values (:zahl);'; Form1.ZQuery1.Prepare; p := Form1.ZQuery1.ParamByName('Zahl'); for a := 1 to testzahl do begin p.AsInteger := a; Form1.ZQuery1.ExecSQL; end; Form1.ZQuery1.SQL.Text := 'Commit;'; Form1.ZQuery1.ExecSQL; end; |
AW: Kleiner Geschwindigkeitstest von Insert
Hallo,
seid Ihr sicher, dass die Transaktionssteuerung so funktioniert? Ich arbeite nicht mit ZEOS, aber ein schnelles googeln brachte zu Tage, dass wenn die Zeos-Connection AutoCommit=True eingestellt hat, dann macht sie das auch, d.h. nach jedem Statement wird ein Commit gemacht, auch nach dem begin transaction. Über das Connection-Objekt kann man mit den Methoden StartTransaction, Commit und Rollback die Transaktionssteuerung "richtig" machen. Leider hast Du nicht das ganze Projekt hier gepostet, somit musst Du es selber ausprobieren :-) Gruß |
AW: Kleiner Geschwindigkeitstest von Insert
Zitat:
Delphi-Quellcode:
Der weiter oben beschriebene Aufruf wäre dann:
function test3a(qry : TZQuery; testzahl: integer): string;
var a: integer; p: TParam; begin qry.SQL.Text := 'begin transaction;'; qry.ExecSQL; qry.SQL.Text := 'Insert into daten2 (zahl) values (:zahl);'; qry.Prepare; p := qry.ParamByName('Zahl'); for a := 1 to testzahl do begin p.AsInteger := a; qry.ExecSQL; end; qry.SQL.Text := 'Commit;'; qry.ExecSQL; end;
Delphi-Quellcode:
Wobei das auch noch schöner ginge.
Form1.ZQuery1.SQL.Text := 'Delete from daten2';
Form1.ZQuery1.ExecSQL; test3a(Form1.ZQuery1,testzahl); Befinden sich Test3a ... im Quelltext von Form1, dann ist das hier überflüssig.
Delphi-Quellcode:
Kann SQLite eigentlich auch
ZQuery1.SQL.Text := 'Delete from daten2';
ZQuery1.ExecSQL; test3a(ZQuery1,testzahl);
Delphi-Quellcode:
ZQuery1.SQL.Text := 'truncate table daten2';
ZQuery1.ExecSQL; test3a(ZQuery1,testzahl); |
AW: Kleiner Geschwindigkeitstest von Insert
bnreimer:
Die Transaction läuft über SQLite, nicht über Zeos ( siehe auch Test8 ohne Transaction und Test9 mit Transaction). Welche Funktion die AutoCommit bei Zeos haben soll bzw. wie man sie einsetzt weiß ich nicht; Scheint bei SQLite nicht notwendig zu sein. Testhalber habe ich AutoCommit mal False, mal True gemacht; Jedoch ohne Unterschied. Aber wie gesagt, ich kenne mich bei dem AutoCommit von Zeos nicht aus. truncate kennt SQLite nicht. |
AW: Kleiner Geschwindigkeitstest von Insert
Zitat:
Aber ZEOS steuert diese und es ist ein Unterschied, ob man ein Skript schreibt oder mit Delphi Komponenten arbeitet. Und es kommt auch drauf an, welche Komponenten man nimmt, ob eine Query oder eine Skriptkomponente. Um das sicher zu wissen, muss man sowohl bei SQLLITE als auch bei ZEOS schauen, wie das Transaktionshandling ist oder zusätzlich über einen Monitor schauen, was die Kommunikation zwischen Client und Server macht. Aber ist natürlich nur nötig, wenn man es ganz genau wissen will und davon gehe ich aus, wenn man schon einen Benchmark schreibt. Gruß |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:23 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz