Discussion:
Speicherverbrauch bei Insert-Statements
(zu alt für eine Antwort)
A. Kuckelberg
2011-11-26 23:39:21 UTC
Permalink
Hallo NG,
ich füge in eine Firebird-DB per TIBQuery-Objekt viele Datensätze über
prepared-Statements ein. Grob sieht der Code so aus:

// Datenbankverbindung einrichten
IBConn := TIBDatabase.Create(nil);
IBConn.DatabaseName := <Datenbankstring>;
IBConn.Params.Add('user_name=' + <User_Name>);
IBConn.Params.Add('password=' + <Password>);
IBConn.LoginPrompt := false;
IBConn.Open;

// Query anlegen
IBQuery := TIBQuery.Create (nil);
IBQuery.Database := IBConn;
IBQuery.CachedUpdates := False;
IBQuery.DisableControls;
IBQuery.SQL.Clear;
IBQuery.SQL.Add ('INSERT INTO tabelle (ID, WERT) VALUES (:id, :wert)');

// Und jetzt viele Werte schreiben
for i := 0 to 100000 do begin
IBQUERY.ParamByName ('ID').AsInteger := i;
IBQUERY.ParamByName ('WERt').AsInteger := i;
IBQUERY.EXECSQL;
end;
IBQUERY.FREE;

Das Problem ist nun, dass nach der Schleife der Speicherverbrauch des
ausführenden Programms stark gestiegen ist (laut Taskmanager). Die
Speichernutzung geht auch nach dem Free nicht zurück. Verwendet wird der
Firebird-Embedded-Server 2.1.4 bzw. 2.5.

Nach meinem bisherigen Verständnis sollte doch die Speichernutzung
innerhalb der Schleife einigermaßen konstant bleiben oder zumindest nach
der Schleife wieder freigegeben werden, oder?

Handelt es sich hier um ein Speicherleck? Ist der Ansatz und die
Erwartung mit "konstanter" Speicherauslastung innerhalb der Schleife
falsch oder ist die Datenbankverbindung oder die Query falsch konfiguriert?

Das gleiche Verhalten zeigt sich auch, wenn statt TIBQuery TIBSQL
verwendet wird.

Hinweise oder weitere Hilfe wäre hier sehr willkommen.
Danke!

Alexander
A. Kuckelberg
2011-11-28 22:41:58 UTC
Permalink
Hallo zusammen,
inzwischen habe ich rausgefunden, dass ein IBConn.Close gefolgt von
einem IBConn.Open die Speichernutzung wieder runterdrückt (aber ein
Commit einer im Beispiel vergessenen Transaktion hat keine Auswirkung).
Scheinbar werden die Insert-Werte gepuffert, das wirkliche Schreiben auf
Festplatte erfolgt wohl erst mit dem Clode/Open.
Gibt es explizite Flush-Anweisungen, um diesen open/close-Umweg zu
vermeiden? Oder Parameter/Konfigurationseinstellungen, die das Ganze
direkt Speicherschonender handhaben?
Alexander
Post by A. Kuckelberg
Hallo NG,
ich füge in eine Firebird-DB per TIBQuery-Objekt viele Datensätze über
// Datenbankverbindung einrichten
IBConn := TIBDatabase.Create(nil);
IBConn.DatabaseName := <Datenbankstring>;
IBConn.Params.Add('user_name=' + <User_Name>);
IBConn.Params.Add('password=' + <Password>);
IBConn.LoginPrompt := false;
IBConn.Open;
// Query anlegen
IBQuery := TIBQuery.Create (nil);
IBQuery.Database := IBConn;
IBQuery.CachedUpdates := False;
IBQuery.DisableControls;
IBQuery.SQL.Clear;
IBQuery.SQL.Add ('INSERT INTO tabelle (ID, WERT) VALUES (:id, :wert)');
// Und jetzt viele Werte schreiben
for i := 0 to 100000 do begin
IBQUERY.ParamByName ('ID').AsInteger := i;
IBQUERY.ParamByName ('WERt').AsInteger := i;
IBQUERY.EXECSQL;
end;
IBQUERY.FREE;
Das Problem ist nun, dass nach der Schleife der Speicherverbrauch des
ausführenden Programms stark gestiegen ist (laut Taskmanager). Die
Speichernutzung geht auch nach dem Free nicht zurück. Verwendet wird der
Firebird-Embedded-Server 2.1.4 bzw. 2.5.
Nach meinem bisherigen Verständnis sollte doch die Speichernutzung
innerhalb der Schleife einigermaßen konstant bleiben oder zumindest nach
der Schleife wieder freigegeben werden, oder?
Handelt es sich hier um ein Speicherleck? Ist der Ansatz und die
Erwartung mit "konstanter" Speicherauslastung innerhalb der Schleife
falsch oder ist die Datenbankverbindung oder die Query falsch konfiguriert?
Das gleiche Verhalten zeigt sich auch, wenn statt TIBQuery TIBSQL
verwendet wird.
Hinweise oder weitere Hilfe wäre hier sehr willkommen.
Danke!
Alexander
Thomas Steinmaurer
2011-11-29 20:41:33 UTC
Permalink
Post by A. Kuckelberg
Hallo NG,
ich füge in eine Firebird-DB per TIBQuery-Objekt viele Datensätze über
// Datenbankverbindung einrichten
IBConn := TIBDatabase.Create(nil);
IBConn.DatabaseName := <Datenbankstring>;
IBConn.Params.Add('user_name=' + <User_Name>);
IBConn.Params.Add('password=' + <Password>);
IBConn.LoginPrompt := false;
IBConn.Open;
// Query anlegen
IBQuery := TIBQuery.Create (nil);
IBQuery.Database := IBConn;
IBQuery.CachedUpdates := False;
IBQuery.DisableControls;
IBQuery.SQL.Clear;
IBQuery.SQL.Add ('INSERT INTO tabelle (ID, WERT) VALUES (:id, :wert)');
// Und jetzt viele Werte schreiben
for i := 0 to 100000 do begin
IBQUERY.ParamByName ('ID').AsInteger := i;
IBQUERY.ParamByName ('WERt').AsInteger := i;
IBQUERY.EXECSQL;
end;
IBQUERY.FREE;
Das Problem ist nun, dass nach der Schleife der Speicherverbrauch des
ausführenden Programms stark gestiegen ist (laut Taskmanager). Die
Speichernutzung geht auch nach dem Free nicht zurück. Verwendet wird der
Firebird-Embedded-Server 2.1.4 bzw. 2.5.
Nach meinem bisherigen Verständnis sollte doch die Speichernutzung
innerhalb der Schleife einigermaßen konstant bleiben oder zumindest nach
der Schleife wieder freigegeben werden, oder?
Handelt es sich hier um ein Speicherleck? Ist der Ansatz und die
Erwartung mit "konstanter" Speicherauslastung innerhalb der Schleife
falsch oder ist die Datenbankverbindung oder die Query falsch konfiguriert?
Das gleiche Verhalten zeigt sich auch, wenn statt TIBQuery TIBSQL
verwendet wird.
Hinweise oder weitere Hilfe wäre hier sehr willkommen.
Danke!
Vermutlich arbeitet das Ganze in einer Art AutoCommit Modus, das
wiederum CommitRetaining verwendet und somit verhindert, dass die
OIT/OAT nachfahren kann.

Ich würde es mit einer expliziten Transaktion versuchen, die außerhalb
der Schleife gestartet und dann innerhalb der Schleife periodisch mit
Commit (nicht CommitRetaining) bestätigt wird.

Für das INSERT würde ich auch ein TIBSQL statt einer TIBQuery verwenden.
--
With regards,
Thomas Steinmaurer

* Firebird Foundation Committee Member
http://www.firebirdsql.org/en/firebird-foundation/

* Upscene Productions - Database Tools for Developers
http://www.upscene.com/

* My Blog
http://blog.upscene.com/thomas/index.php
A. Kuckelberg
2011-11-30 14:44:00 UTC
Permalink
Post by Thomas Steinmaurer
Vermutlich arbeitet das Ganze in einer Art AutoCommit Modus, das
wiederum CommitRetaining verwendet und somit verhindert, dass die
OIT/OAT nachfahren kann.
Ich würde es mit einer expliziten Transaktion versuchen, die außerhalb
der Schleife gestartet und dann innerhalb der Schleife periodisch mit
Commit (nicht CommitRetaining) bestätigt wird.
Für das INSERT würde ich auch ein TIBSQL statt einer TIBQuery verwenden.
Hoi und vielen Dank für die Anregung.
Leider bringt es keinerlei Erfolg, rumspielen mit den Transaktionen
(Commit, CommitRetaining) hat keine Auswirkung auf die Speichernutzung.
Arno Garrels
2011-11-30 16:16:14 UTC
Permalink
Post by A. Kuckelberg
Das Problem ist nun, dass nach der Schleife der Speicherverbrauch des
ausführenden Programms stark gestiegen ist (laut Taskmanager). Die
Speichernutzung geht auch nach dem Free nicht zurück. Verwendet wird der
Firebird-Embedded-Server 2.1.4 bzw. 2.5.
Nach meinem bisherigen Verständnis sollte doch die Speichernutzung
innerhalb der Schleife einigermaßen konstant bleiben oder zumindest nach
der Schleife wieder freigegeben werden, oder?
Handelt es sich hier um ein Speicherleck?
Schwer zu sagen. Falls du mit "Speicherverbrauch" die Zeile
Speicherauslastung des Taskmanagers meinst, kann man daraus nicht
viel ableiten, weil das nur die Größe des Working Sets ist, das z.B.
schrumpft, wenn man die Anwendung mimimiert.
Entscheidend ist die Größe des tatsächlich reservierten Speichers.
Dieser Wert hieß im XP Taskmanager Virtueller Speicher, im Process
Explorer unter Performance | Virtual Memory Private Bytes.
Wenn dieser Wert bei mehreren Durchläufen nicht stetig ansteigt
sollte es kein Leck sein.
--
Arno Garrels
Lesen Sie weiter auf narkive:
Loading...