Methoden einen Datensatz in Datenbank zu schreiben

Ich benutze schon lange cubesql und bin jetzt auf Geschwindigkeitsprobleme beim Zugriff übers Web (dyndns) gestoßen.

Bisher schreibe ich meine Datensätze klassisch, also so:

Dim row As New DatabaseRecord
for i= 0 to listbox.listcount-1
row=new DatabaseRecord
row.Column(“Name”) = listbox1.cell(i,0)
row.Column(“Coach”) = listbox1.cell(i,1)
row.Column(“City”) = listbox1.cell(i,2)
usw…
db.InsertRecord(“Team”, row)
next

Marco, der cubesql programmiert, meinte ich würde damit zu viel Netzwertraffik erzeugen, ich solle das mit Bind machen. Da cubeSql die Xojo PreparedSQlStatements nicht unterstützt, muss ich auf die cubesqlvm Methoden zurückgreifen.

Meine Frage ist nun, gibt es noch eine andere Möglichkeit hier deutlich die Geschwindigkeit zu erhöhen bzw. den Netzwerktraffik zu reduzieren? Wie ist es denn mit „Insert into“?
Ich muss hier sagen, das ich zwar schon lange RB benutze, mich aber nicht intensiv mit Datenbanken beschäftigt habe, weil ja alles prima lief, ich bin also über die klassichen/einfachen Lese-Und Schreibzugriffe nicht hinaus gekommen!

Der Netzwerktraffic erscheint mir als vernachlssigbar. Ich gehe davon aus, dass Du nicht Tausende von Listboxzeilen in die Datenbank schreibst. Aber sogar dann ist das nicht etwas was wohl andauernd gemacht wird.

Eine andere Sache ist die Ausfhrzeit. Wenn automatisch nach jedem Insert ein Commit ausgefhrt wird, dann wird es ghnend langsam. Das Ganze sollte in eine Transaktion gepackt werden und erst nach dem letzten Insert sendest Du ein Commit.

Wenn Du in einem Loop mit insertrecord arbeitest, dann solltest Du auch sicherstellen, dass Du beim CubeSQLServer AUTOCOMMIT auf OFF stellst und dann eben den Insert Loop in eine Transaction packst.

Nach dem Loop sendest Du selber einen COMMIT an die Datenbank und setzt AUTOCOMMIT anschliessend wieder auf die ursprngliche Einstellung. Die Autocommit Einstellung gilt nur fr die aktuelle Verbindung.

Aus dem CubeSQL Handbuch:

[quote]Server by default is in AUTOTRANSACTION mode, that means that every INSERT, UPDATE,
DELETE sql operation is automatically executed inside a TRANSACTION that must be
COMMITTED or ROLLEDBACK at the end. If you want to change the default behavior you
can set AUTOCOMMIT to ON, that means that an implicit COMMIT is executed after every
WRITE operation. This is a PER CONNECTION property and not a global server or a global
database property. Please note that AUTOTRANSACTION cannot be turned ON when
MVCC is enabled.[/quote]

Beispiel aus Commands Ref.pdf von CubeSQL:

db = New CubeSQLServer db.Host = "localhost" db.port = 4430 db.UserName = "admin" db.Password = "admin" If (db.connect = false) then MsgBox "Connect error: " + db.ErrorMessage return end if db.SQLExecute("SET AUTOCOMMIT TO ON;") If db.error then MsgBox "An error occurred: " + db.ErrorMessage

Danke ich teste das heute Abend!

Leider dauert das 10 Sekunden bei 12 Zeilen in der Listbox, egal ob ich Autocommit on oder off habe, das hat bei mir überhaupt keine Auswirkungen. Auf beiden Seiten habe ich DSL16 mit effektiven 12Mbit. Der Server ist ein alter iMac Core2Duo mit 10.7

Hat dazu jemand noch eine Idee???

dbfakt.SQLExecute("SET AUTOCOMMIT TO OFF;")
dbfakt.SQLExecute( "BEGIN TRANSACTION;" )

for i=0 to listbox1.listcount-1
r=new DatabaseRecord
r.Column(“feldo”)= nr
r.Column(“felda”) =listbox1.cell(i,0)
r.Column(“feldg”) =listbox1.cell(i,1)
r.Column(“feldh”) =listbox1.cell(i,2)
r.Column(“feldi”) =listbox1.cell(i,3)
usw 21 Felder insgesamt
dbfakt.InsertRecord(“dbauftragpos”,r)
end if
next
dbfakt.SQLExecute( “COMMIT;” )
dbfakt.SQLExecute(“SET AUTOCOMMIT TO ON;”)

Hast Du mal versucht nach dem ersten SQLExecute einen Commit zu senden?

z.B.:

CubeSQLServer.Commit

… und nach dem letzten .SQLExecute dann natürlich auch wieder.

Hab ich gerade versucht ohne Erfolg, es ndert sich nach wie vor nichts an der Geschwindigkeit.
Im Server Log steht auch nichts drin? Ich habe die aktuelle Version 4.5 laufen.

Wie gro ist Dein Datensatz? Wie sieht es mit der Geschwindigkeit aus, wenn die Datenbank lokal liegt?

Der Datensatz bestht aus 21 Felder, in denen jeweils max 100 Buchstaben text drin stehen. Lokal ist da nichts zu merken, selbst wenn ich dort 300 Zeilen schreibe, geht das super fix.
Im lokalen Netzwerk mit dem cubeserver merkt man aber dann den Unterschied schon, wobei das nicht schmerzt bei 1000 Ethernet.
Aber dann übers Web ist es eine Zumutung.

Ich dachte auch, das was Oliver vorgeschlagen hatte müsste etwas bringen… aber aus mir nicht bekannten Gründen hat sich nichts geändert.

21 * 100 ist nicht viel. Also entweder ist das Netzwerk beschftigt oder die Datenbank.

Ich weiss, ich bin vor lngerer Zeit genau dadrber auch gestolpert… leider kann ich mich nicht mehr erinnern, was ich dann alles getestet habe. Wenn ich jetzt in den entsprechenden Code schaue, dann fllt mir auf, dass ich da nicht mehr die InsertRecord Methode mit DatabaseRecord Objekten verwende, sondern klassisches SQL. Das luft dann auch bei mehreren Tausend Inserts ganz zgig (AutoCommit OFF und Commit erst nach dem letzten Insert!).

An Deiner Stelle wrde ich mal testen, das SQL Insert statement selber zusammenzusetzen und per SQLExecute an den Server zu senden.

http://www.sqlite.org/lang_insert.html

zu Beatrix: ich teste es morgen nochmal mit einer neuen, leeren DB

zu Oliver: könntest du mir bitte aus deinem Code ein kleines Beispiel hier posten? Hast du das so laufen wir ich? Also Server und du greifst übers Web drauf zu?

Alternativ ist da noch Marcos Vorschlag mit Prepare und Bind…

Ich habe einen produktiven Server und 3 Testserver auf die ich regelmssig auch ber eine Internetverbindung zugreife. Das funktioniert berall ganz zgig.

Ein Beispiel fr ein kurzes SQL Insert statement:

' Example: imDB.SQLexecute ("Insert into Employees(Name,Department,Salary,VacationDays) "_ +"Values ('Seymore','Accounting',5000,0)")

Das hier aus dem hohlen Bauch raus, nicht getestet:

[code] Dim db As CubeSQLServer
db.AutoCommit = False
db.Commit

For i As Integer = 1 To 1000
Dim sql As String = "Insert into Employees(Name,Department,Salary,VacationDays) "_
+“Values (‘Seymore’+Str(i),‘Accounting’,5000,0)”
db.SQLExecute(sql)
Next
db.Commit

db.AutoCommit = True
db.Commit
[/code]

Ohne dass ich was zur Geschwindigkeit beitragen kann, möchte ich Dich jedoch sensibel und aufmerksam machen wie Deine Art der Speicherung fahrlässig ist. Du schreibst ohne Überprüfung auf SQL Injections oder Sonderzeichen wie Hochkommas etc. und ohne UTF8 Encodierung den Zelleninhalt einer Listbox in eine DB rein. Auch ist es kein guter Programmierstil ohne wiederverwendbare Objekte zu programmieren (erstelle z.B. ein Objekt TeamMember), auf try…catch Exceptionhandling zu verzichten und db.error Auswertungen komplett zu ignorieren.

Jetzt fällt mir aber doch ein Hinweis ein, der vielleicht die Geschwindigkeit verbessern könnte:
Versuche die Listbox vor der Schleife auszublenden und setze #pragma Backgroundtasks auf false

[quote=110562:@Tomas Jakobs]Ohne dass ich was zur Geschwindigkeit beitragen kann, möchte ich Dich jedoch sensibel und aufmerksam machen wie Deine Art der Speicherung fahrlässig ist. Du schreibst ohne Überprüfung auf SQL Injections oder Sonderzeichen wie Hochkommas etc. und ohne UTF8 Encodierung den Zelleninhalt einer Listbox in eine DB rein. Auch ist es kein guter Programmierstil ohne wiederverwendbare Objekte zu programmieren (erstelle z.B. ein Objekt TeamMember), auf try…catch Exceptionhandling zu verzichten und db.error Auswertungen komplett zu ignorieren.

Jetzt fällt mir aber doch ein Hinweis ein, der vielleicht die Geschwindigkeit verbessern könnte:
Versuche die Listbox vor der Schleife auszublenden und setze #pragma Backgroundtasks auf false[/quote]
Die Information der Encodierung geht beim Schreiben in die Datenbank verloren. Die Applikation, bzw der Programmierer, muss beim Einlesen wissen um was es sich handelt und diese Information wieder hinzufügen.

Den Tip die Listbox auf .visible = false zu setzen würde ich ausprobieren. Ich weiss nicht wieviel es beim Auslesen von Daten bringt, aber wenn man in eine Listbox schreibt, d.h. z.B. das Resultat eines SELECT in einer Listbox anzeigt, dann bringt das vorherige Ausblenden sehr viel an Performance.

Punkto Sicherheit müssen bei den hier bis anhin aufgeführten Methoden auf jeden Fall eine Input Validierung hinzugefügt werden. Z.B. müssen Hochkomma verdoppelt werden vor dem Schreiben in die Datenbank, und mehr.

Prepared Statements sind sicherer, und mit CubeSQLVM möglich.

Beispiel für CubeSQLVM:

[code] Dim ps As CubeSQLVM = db.Prepare(“select * From Residents Where ID = ? And Age >= ?”)

ps.BindText(1, “john”)
ps.BindInt(2, 20)

Dim rs As RecordSet = ps.VMSelect()[/code]

Die Vorschlge mit .visible = false und den pragmas knnen nicht wirklich so viel ausmachen. Bei 10 Sekunden fr so ein kleines Update ist irgendetwas im Hintergrund am Laufen.

Ich teste es morgen mit Insert Into, da bin ich jetzt doch sehr gespannt. Leider ist heute Sonntag und mein Server im Büro fährt dann nicht automatisch hoch…

Auf dem Server-iMac läuft sonst gar nicht, auf eine frische 10.7 Installation habe ich den cubesqlServer installiert. Ok, das Tool von dyndns läuft dort auch noch.

Das mit der Listbox spielt doch hier erst mal keine Rolle, da ich lächerliche 10 Zeilen aus der Listbox lese und übertrage.

Da ich weiß, wie lange ein commit dauert, könnten Olivers Vorschläge die Richtigen sein… morgen weiß ich mehr. Was ich nur nicht verstehe, warum der cube Server bei db.insertrecord länger brauchen soll bzw. immer ein commit macht und bei insert into nicht.

Wenn alle Versuche im Code scheitern, wre der Server selbst das Ziel der Untersuchung. Einer meiner Kunden hatte auch einmal Performance Probleme mit einem mySQL Server und meiner Software. Eine Untersuchung des Servers brachte hervor, dass DNS Namensaufsungen durch Filter und Firewallregeln extrem langsam waren und Ursache fr lange Verbindungsaufbauten waren. Stand jedoch einmal eine Verbindung zum Server, ging alles wieder flott.

Wenn es sich herausstellen sollte, dass Du hierbei einen deutlichen Performance Unterschied messen kannst, dann wäre dies wohl ein Bug im Code von Marco Bambini (marco at sqlabs.com). Da könntest Du ihn mal dazu anfragen.

Bis Dienstag werde ich all das testen können… dann poste ich hier die Resultate.