# Performance von Entity Bean create vs. JDBC insert



## ichbindiegute (27. Mai 2007)

Hallo!

Ich schreibe gerade an meiner Diplomarbeit zum Thema Reengineering einer Java Bibliothek und Portierung dieser in eine J2EE Umgebung mit EJB.

Ich benutze
Application Server: JBoss 4.0.2
Datenbank: ORACLE 10xe
EJB 2.0

Meine Frage bezieht sich auf Performance:
Es werden 160 Datensätze in eine Datenbanktabelle eingetragen. Die Programmlogik erzeugt ungefähr 400 JDBC insert Statements, die natürlich zu ungefähr 240 SQL Errors führen wegen DUPLICATE KEYS. Dies ist aber kein Problem.

In der neuen Version benutze ich Entity Beans, um genau dieselben Daten in die Datenbank einzutragen. Auch hier kommt es natürlich zu ungefähr 240 CreateExceptions.

Meine Frage: Wie kann es sein, dass die JDBC Aufrufe insgesamt etwa 150% MEHR Zeit beanspruchen, als die Entity Bean create Aufrufe? Wie kann der Application Server die Performance so stark erhöhen?

Ich bin dankbar für jeden Hinweis!

Viele Grüße,
Monika


----------



## semi (27. Mai 2007)

ichbindiegute hat gesagt.:
			
		

> Meine Frage: Wie kann es sein, dass die JDBC Aufrufe insgesamt etwa 150% MEHR Zeit beanspruchen, als die Entity Bean create Aufrufe? Wie kann der Application Server die Performance so stark erhöhen?


Statement-Cache. Die Insert-Statements werden gecached und immer wieder verwendet.

Es hängt auch davon ab, was du mit direktem JDBC machst. Ich würde sagen, JDBC sollte um einiges schneller 
sein, da man hier nicht den ganzen Overhead des Application Servers hat.


----------



## ichbindiegute (28. Mai 2007)

Soweit ich das verstanden habe, kann man einen Prepared-Statement-Cache für JBoss in der oracle-ds.xml konfigurieren. Der entsprechende Tag lautet prepared-statement-cache-size und gibt die Anzahl der Prepared Statements an, die der Cache halten kann. 

Allerdings habe ich diesen Tag gar nicht verwendet und (Zitat JBoss Server Handbuch) "ohne Angabe dieses Elements ist der Cache abgeschaltet".



			
				semi hat gesagt.:
			
		

> Ich würde sagen, JDBC sollte um einiges schneller
> sein, da man hier nicht den ganzen Overhead des Application Servers hat.



Das würde ich auch sagen. Und trotzdem ist der Application Server dermaßen viel schneller. 

Ich bin natürlich froh über die Performancesteigerung, dennoch würde ich gern etwas über die Gründe erfahren.

Irgendwelche weiteren Ideen?


----------



## bronks (28. Mai 2007)

ichbindiegute hat gesagt.:
			
		

> ...
> Das würde ich auch sagen. Und trotzdem ist der Application Server dermaßen viel schneller.
> 
> Ich bin natürlich froh über die Performancesteigerung, dennoch würde ich gern etwas über die Gründe erfahren.
> ...


Das liegt daran, daß der AS die Entities cached. Es wird eine CreateException geschmissen, ohne erst in der DB den Key zu prüfen, da der AS dank caching bereits weiß, daß dieser bereits existiert.


----------



## Guest (29. Mai 2007)

> Das liegt daran, daß der AS die Entities cached. Es wird eine CreateException geschmissen, ohne erst in der DB den Key zu prüfen, da der AS dank caching bereits weiß, daß dieser bereits existiert.



Diese Lösung fand ich prima. Vor allem habe ich in einem anderen Forum eine übereinstimmende Antwort bekommen:


> Ich würde darauf tippen, das die Entity Beans sich bereits im Cache befinden. Dann weiß der JBoss das z.b. ein key bereits existiert ohne einen insert auf die Datenbank zu machen.
> 
> 
> 
> ...


----------



## ichbindiegute (29. Mai 2007)

> Das liegt daran, daß der AS die Entities cached. Es wird eine CreateException geschmissen, ohne erst in der DB den Key zu prüfen, da der AS dank caching bereits weiß, daß dieser bereits existiert.



Diese Lösung fand ich prima. Vor allem habe ich in einem anderen Forum eine übereinstimmende Antwort bekommen:


> Ich würde darauf tippen, das die Entity Beans sich bereits im Cache befinden. Dann weiß der JBoss das z.b. ein key bereits existiert ohne einen insert auf die Datenbank zu machen.



Aber ich kann durch die DEBUG Log Meldungen des AS sehen, dass er wirklich jedesmal ein INSERT Statement an die Datenbank schickt. :-(

Eine andere Lösung wäre, dass der Application Server nicht auf die Antwort der Datenbank wartet, sondern asynchron vorgeht. Aber das kann auch nicht sein, da er direkt nach dem INSERT Statement die CreateException wirft.

Weitere Vorschläge?


----------



## bronks (29. Mai 2007)

ichbindiegute hat gesagt.:
			
		

> ... Aber ich kann durch die DEBUG Log Meldungen des AS sehen, dass er wirklich jedesmal ein INSERT Statement an die Datenbank schickt. :-( ...


Da bin ich jetzt überrascht. Bitte wirf einen Blick in den Log der DB, um herauszufinden, ob der AS tatsächlich den Insert wegschickt.


----------



## ichbindiegute (29. Mai 2007)

Die CreateException wird von einer SQLException ausgelöst (der entity command no-select-before-insert arbeitet mit der Klasse SQLExceptionProcessor zusammen). Und diese SQLException kann sich der Application Server ja nicht einfach ausdenken. Deshalb gehe ich davon aus, dass die DB das INSERT bekommt ohne in die Logs der DB zu schauen.

Im ursprünglichen System ist auf jeden Fall das JDBC PreparedStatement mit dem INSERT der Bottleneck. Wahrscheinlich ist also nicht der AS unheimlich schnell, sondern das JDBC Statement im alten System unheimlich langsam. (?)


----------



## SnooP (29. Mai 2007)

Kannst du ein langsames Verhalten auch feststellen, wenn du keine Constraints verletzt beim Inserten... sprich Einfügen von 200 Daten mit JDBC und mit ORM? Würde mich halt auch überraschen, wenn das jdbc langsamer sein sollte... man erkennt ja auch, welche Statements produziert werden.. wenn das die gleichen sind wie die aus dem jdbc-teil...nunja  - dann muss noch Magie dabei sein.

Werden denn die gleichen Tabellen benutzt oder nur ähnliche?


----------



## ichbindiegute (29. Mai 2007)

SnooP hat gesagt.:
			
		

> Kannst du ein langsames Verhalten auch feststellen, wenn du keine Constraints verletzt beim Inserten... sprich Einfügen von 200 Daten mit JDBC und mit ORM? Würde mich halt auch überraschen, wenn das jdbc langsamer sein sollte... man erkennt ja auch, welche Statements produziert werden.. wenn das die gleichen sind wie die aus dem jdbc-teil...nunja  - dann muss noch Magie dabei sein.
> 
> Werden denn die gleichen Tabellen benutzt oder nur ähnliche?



Es sind haargenau die gleichen Daten, die in dieselbe Tabelle eingetragen werden. Ich habe jetzt in beiden Modulen (dem alten mit JDBC und dem neuen mit EJB) die Programmlogik geändert, um keine Duplicate Key Exception mehr zu haben. Und im alten Modul wird nicht mehr jedes INSERT einzeln commited sondern in einem batch insert alle Inserts zusammen. 

UND: das neue Modul ist immer noch schneller. Es benötigt 54% der Laufzeit des alten Moduls.

Magie?!


----------



## Tellerrand (29. Mai 2007)

ichbindiegute hat gesagt.:
			
		

> Es sind haargenau die gleichen Daten, die in dieselbe Tabelle eingetragen werden. Ich habe jetzt in beiden Modulen (dem alten mit JDBC und dem neuen mit EJB) die Programmlogik geändert, um keine Duplicate Key Exception mehr zu haben. Und im alten Modul wird nicht mehr jedes INSERT einzeln commited sondern in einem batch insert alle Inserts zusammen.
> 
> UND: das neue Modul ist immer noch schneller. Es benötigt 54% der Laufzeit des alten Moduls.
> 
> Magie?!


Der Unterschied liegt hier zwischen handoptimiertem Code und dem automatisch optimierten Code soviel ist klar. Wobei ich den handoptimeirten Code für nicht ganz optimal halte, es dürften noch einige Möglichkeiten existieren um diesen zu beschleunigen.
Da hilft nur sich direkt an der Datenbank an zu schauen was wie ankommt und weggeht.
Liegt dort kein Unterschied so existiert immernoch die Möglichkeit, dass die Verarbeitung z.B. String Operationen den handoptimeirten Code ausbremsen.


----------



## schalentier (29. Mai 2007)

Wie misst du die Geschwindigkeit im Application Server und im JDBC Programm?

Kann es sein, dass in der JDBC-Zeit die "Anlaufzeit" der VM mit drin ist? Je nach Umgebung ist diese nicht zu vernachlaessigen. Das ist die Zeit, die die Java VM selbst zum Laden braucht, bzw. die benoetigt wird, um genuegend Speicher anzufordern. 

Wieviel Mal wiederholst du den Test, um zu messbaren und einigermassen konstanten Zeiten zu kommen? Sind die Zeiten konstant? Mit welcher Abweichung 

Ich wuerd eher tippen, dass da ein Messfehler drin ist. Ich kann mir nicht vorstellen, dass es an Stringoperationen oder irgendwelchen Caches liegt. Dafuer sind 200 Datensaetze einfach zu wenig...


----------

