# Viel zu langsame DerbyDB



## Paladin (24. Okt 2005)

Hi,

ich versuche gerade in eine Derby Datenbank 200000 Zeilen und mehr einzufügen. Bis zu 10000 Zeilen funktioniert das auch in einer annehmbaren Geschwindigkeit aber alles jenseits von 50000 Zeilen dauert extrem lange. Ich hab zum Beispiel versucht 200000 Zeilen einzufügen und hab den Versuch nach etwas mehr als 10min abgebrochen weils einfach zu lange dauert.

Liegt es an meinem Sourcecode? Ich kann mir eigentlich nicht vorstellen, dass Derby schon bei 50000 Zeilen Probleme bekommt.

Hier also der Sourcecode mit dem ich in die Datenbank einfüge:
_trows = Anzahl der einzufügenden Zeilen (long)
in = BufferedReader(FileReader(File))
_


```
for(i1=0;i1<trows;i1++) {
      try {				
         hsqlstatement.execute(in.readLine());			
      } catch (Exception e) {
         e.printStackTrace();
      }
}
```

*Die Tabelle Vergleich wird mit folgendem sql Befehl angelegt:*
CREATE TABLE Vergleich(KVNr INTEGER,UKVNr INTEGER,AG INTEGER,GNR VARCHAR(7),Quartal INTEGER,Jahr INTEGER,VerglWert REAL,Anzahl REAL,Faelle REAL,Fikt INTEGER,Neu INTEGER,Arztnummer VARCHAR(10),PKey BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1,INCREMENT BY 1))

*Die Datei beinhaltet INSERT INTO Statements. Diese Statements sehen alle folgendermaßen aus:*
INSERT INTO Vergleich(KVNr,UKVNr,AG,GNR,Quartal,Jahr,VerglWert,Anzahl,Faelle,Fikt,Neu,Arztnummer) VALUES(1,1,14,'01100',2,2005,0.5847411,189.0,0.0,1,0,null)


Ich würde mich freuen, wenn mir jemand von euch einen Tipp geben könnte an welcher Stelle mein Denkfehler liegt.

Vielen Dank im voraus

Gruß

Paladin


----------



## AlArenal (24. Okt 2005)

Pack mal alle INSERTs in EINE Transaktion.


----------



## Paladin (24. Okt 2005)

Hast du eine URL zu einem Tutorial wie man eine Transaction erstellt?


----------



## AlArenal (24. Okt 2005)

Mache für deine Connection conn mal ein

```
conn.setAutoCommit(false);
```

Dann machst du alle deine INSERTs und anschließend ein COMMIT.

Literatur:
http://db.apache.org/derby/docs/10.0/manuals/develop/develop63.html


----------



## bronks (24. Okt 2005)

Paladin hat gesagt.:
			
		

> ... Derby Datenbank 200000 Zeilen und mehr einzufügen. Bis zu 10000 Zeilen funktioniert das auch in einer annehmbaren Geschwindigkeit aber alles jenseits von 50000 Zeilen dauert extrem lange. Ich hab zum Beispiel versucht 200000 Zeilen einzufügen und hab den Versuch nach etwas mehr als 10min abgebrochen weils einfach zu lange dauert.


Ich kenn Derby nicht und hab keine Ahnung was für Geschwindigkeiten Du erwartest. Mit den gängigen Datenbanken erreiche ich mit den zur Zeit schnellsten 1-CPU-IntelRechnern so ca. +- 1000 Inserts je Minute. Bei Deinen 200000 Zeilen solltest Du bei solchen Geräten knappe 4 Stunden Geduld mitbringen. Das hängt auch davon ab, wie die DB-Tabelle indiziert ist und in welcher Reihenfolge die Daten in der Textdatei stehen.


----------



## Paladin (24. Okt 2005)

Mit setAutocommit(false) ist es zwar schon schneller aber die Geschwindigkeit ist immer noch nicht akzeptabel. Vielleicht muss ich ja eine andere Datenbank benutzen?

@bronks: Es muss doch eine Möglichkeit geben Daten schneller in die DB zu bekommen. 200000 Zeilen sind ja nun auch nicht gerade sooo viel. 

Gruß

Paladin


----------



## robertpic71 (24. Okt 2005)

Also ich denke auch, dass die Anforderungen etwas hoch geschraubt sind. Unser bestes Pferd im Stall (DB2 auf PowerPC) schafft knapp 50.000 INSERTS pro Minute (300 Byte Satzlänge, 1 Index).

Wie AlArenal bereits geschrieben hat, ist das Autocommit ein ziemlicher Bremser. Allerdings kann eine große Transaktion für 100.000 Sätze (zumindest für laut IBM DB2 Doku) auch in schlechte Perfomance ausarten. Bei uns im Haus hat sich für Massenverarbeitung ein COMMIT alle 2000-5000 Sätze (je nach Satzlänge) eingebürgert. 

Bei Tip's und Tricks zur Performance fast aller Datenbanken wird immer auf die Verwendung von PreparedStatements hingewiesen. Ein SQL-Statement muss interpretiert bzw. vorcompiliert werden. Ohne PreparedStatements werden also bei 200.000 INSERT, 200.000 Zeilen vorcompiliert. 

Siehe auch:  db.apache.org/derby/docs/10.0/manuals/tuning/perf34.html

LG Robert


----------



## Bleiglanz (24. Okt 2005)

```
INSERT INTO TwoColumnTable VALUES
    (1, 'first row'),
    (2, 'second row'),
    (3, 'third row')
```
zum einfügen mehrerer Zeilen verwenden (auch JDBC Batch Verarbeitung beachten...)

und probiermal


```
java -Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver
    org.apache.derby.tools.ij < diedateimitdeninserts.sql
```


----------



## bronks (24. Okt 2005)

Paladin hat gesagt.:
			
		

> @bronks: Es muss doch eine Möglichkeit geben Daten schneller in die DB zu bekommen. 200000 Zeilen sind ja nun auch nicht gerade sooo viel.


Natürlich gibt es die. Du verwendest dafür leider die absolut falsche Technik. Da steckt sehr viel Aufwand dahinter von einem Client (in dem Fall Java) einen Insert an eine DB zu schicken. Zum einen hat man Netzwerkverkehr, der erstmal erzeugt werden muß. Der Client muß dem Server die Hand schütteln im sagen, was er haben will und dann das ganze rückwärts, weil der Client wissen will, ob der Server auch seine Arbeit gemacht hat. Zum anderen belastet man die Netzwerkdienste , welche auch noch ordentlich Leistung haben wollen. Große Transaktionen helfen zwar dabei diesen Aufwand zu reduzieren, sind dafür aber eigentlich nicht gedacht.

Wenn Du Dein SQL-Script direkt an den Server richtest bzw. gegen den Server ausführst, dann kannst Du damit rechnen, daß > 10000 Inserts pro Sekunde durchlaufen werden.


----------



## Paladin (24. Okt 2005)

@Bleiglanz
Wenn ich einen Datensatz nach dem von dir angegebenen Schema (INSERT INTO TwoColumnTable VALUES 
(1, 'first row'),(2, 'second row'),(3, 'third row')) einfügen will bekomme ich

ERROR 42X61: Types 'INTEGER' and 'CHAR' are not UNION compatible.

von Eclipse zurück.

Ist mein Statement nicht korrekt?


```
INSERT INTO Vergleich VALUES (1,'KVNr'),(1,'UKVNr'),(14,'AG'),('01100','GNR'),(2,'Quartal'),(2005,'Jahr'),(0.5847411,'VerglWert'),(189.0,'Anzahl'),(0.0,'Faelle'),(1,'Fikt'),(0,'Neu'),(null,'Arztnummer')
```


----------



## Exceptionist (24. Okt 2005)

ÖÖÖÖHHHM, was hälst du denn davon eine andere Datenbank zu benutzen??
oder ist diese derby-database zwingend notwendig??

ich hab zwar nur grundlagenwissen, aber wenn du die einzutragenden werte als datei irgendwo hast, kannst du das doch auch über das datenbanksystem machen oder nicht?

also bei Oracle9i und MySQL geht das.


----------



## Bleiglanz (24. Okt 2005)

(1,'KVNr'),
(1,'UKVNr'),
(14,'AG'),
('01100','GNR'), // HÄ?? warum als erstes Arg ein Char??


die Spaltentypen müssen schon stimmen??


----------



## Paladin (24. Okt 2005)

@Bleiglanz:

Ich hab das folgendermaßen verstanden:

INSERT INTO TwoColumnTable VALUES 
    (Wert, 'Name1'), 
    (Wert, 'Name2'), 
    (Wert, 'Name3') 

oder wie meinst du das?

@Exceptionist:
Die DerbyDB ist nicht zwingend vorgegeben. Wenns gar nicht geht wechsel ich auch
wieder zur HSQLDB. Die ist beim einfügen um einiges schneller.


----------



## Exceptionist (24. Okt 2005)

Ach jo, was mir grad mal einfällt...
bei dem insert- vorgang...ähhm du sprichst eine spalte nach der anderen an oder nicht??

wenn du nämlich nur in bestimmte spalten etwas eintragen möchtest, musste die spaltennamen nämlich auch angeben...
ansonsten reicht ein 
insert into tabellenname
values(?,?,?,...usw)


----------



## Paladin (24. Okt 2005)

ja, ich fülle in jede spalte einen wert bei dem insert vorgang.
Ich werde das mit dem weglassen der spaltennamen mal versuchen. Bei 200000 zeilen dürfte selbst das Zeit sparen


----------



## KSG9|sebastian (24. Okt 2005)

INSERT INTO TabelleABC VALUES (wert_spalte1, wert_spalte2..)

Das einzige unterschied ist, dass du nicht mit angibst, welcher Wert auf welche Spalte gemappt wird.

INSERT INTO TabellABC(a, b, c) VALUES(1, 2, 3)

gibt ja folgende Zuordnung vor:

Spalte a wird der Wert 1 zugeordnet
Spalte b wird der Wert 2 zugeordnet
Spalte c wird der Wert 3 zugeordnet


INSERT INTO TabelleABC VALUES (1, 2, 3, 4, 5)

sieht die Zuordnung so aus:

Spalte 1 wird der Wert 1 zugeordnet
Spalte 2 wird der Wert 2 zugeordnet
Spalte 3 wird der Wert 3 zugeordnet
Spalte 4 wird der Wert 4 zugeordnet
Spalte 5 wird der Wert 5 zugeordnet

Dabei musst du beachten, dass du für JEDE Spalte nen Wert mitgibst, d.h. bei ner Tabelle mit 5 Spalten musst du auch genau 5 Werte in der Klammer übergeben


----------



## Exceptionist (24. Okt 2005)

jupp!! mein reden, hab nur nicht die zeit, um so viel zu schreiben
*grins*

aber wenn paladin ja sowieso in jede spalte etwas eintragen möchte, ist das (wie ich denke) die sinnvollste variante...
oder etwa nicht?


----------



## Paladin (24. Okt 2005)

Das mit dem einfügen mit und ohne spaltennamen ist mir schon klar ich war nur verwirrt hat mich
das schema welches Bleiglanz beschrieben hat:



> INSERT INTO TwoColumnTable VALUES
> (1, 'first row'),
> (2, 'second row'),
> (3, 'third row')



Aber ich nehme mal an, dass er das gleiche meinte wie sebastian gerade sehr ausführlich beschrieben hat  :wink:


----------

