SlideShare ist ein Scribd-Unternehmen logo
1 von 51
Downloaden Sie, um offline zu lesen
Speeding up Java Persistence
Dirk Weil, GEDOPLAN GmbH
Dirk Weil
GEDOPLAN GmbH, Bielefeld
Java EE seit 1998
Konzeption und
Realisierung
Seminare
Vorträge
Veröffentlichungen
Speeding up Java Persistence 2
Id-Generierung
Entity-Klassen müssen Id haben
PK in der DB
Feld oder
Property
mit @Id
Empfehlenswert: Technische Id
Problem: Erzeugung eindeutiger Werte
@Entity
public class SomeEntity
{
@Id
private int id;
…
Speeding up Java Persistence 3
Id-Generierung
JPA-Feature: @GeneratedValue
Nutzt DB-Sequenzen,
Identity Columns oder
Sequenz-Tabellen
Probleme:
Id erst nach persist gesetzt
 equals?, hashCode?
Id-Übernahme kostet Zeit
@Id
@GeneratedValue
private int id;
Speeding up Java Persistence 4
Id-Generierung
Alternative: BYO-ID (selbst machen)
Id auch in transitiven Objekten gesetzt
Insert ohne Zusatzaufwand
Achtung: i. A. nicht trivial
Z. B.: UUID
this.id = UUID.randomUUID().toString();
// oder: new com.eaio.uuid.UUID().toString()
Speeding up Java Persistence 5
Id-Generierung
@GeneratedValue langsamer
(OOTB)
Speeding up Java Persistence 6
Id-Generierung
Tuning: Höhere Allocation Size
Leider nicht verfügbar bei IDENTITY
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "ArtikelIdGenerator")
@SequenceGenerator(name = "ArtikelIdGenerator",
allocationSize = 1000)
private int id;@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "ArtikelIdGenerator")
@TableGenerator(name = "ArtikelIdGenerator",
allocationSize = 1000)
private int id;
Speeding up Java Persistence 7
Id-Generierung
Speeding up Java Persistence 8
Relationship Loading
Relationen werden durch Attribute mit @…To… repräsentiert
@Entity
public class Book
{
@ManyToOne
public Publisher publisher;
@Entity
public class Publisher
{
@OneToMany(mappedBy="publisher")
public List<Book> books;
Speeding up Java Persistence 9
Relationship Loading
Relationen-Parameter: fetch
Referenzierte Entities direkt laden?
EAGER: Direkt
LAZY: Später bei Bedarf
@ManyToOne(fetch = FetchType.LAZY)
private Artikel artikel;
Speeding up Java Persistence 10
Relationship Loading
Bsp.: Auftragsposition bearbeiten
n:1-Relation zu Artikel
Kunde Auftrag
Auftrags
Position
ArtikelLand
1 *
1
*
*
1
1*
@Entity
public class AuftragsPosition
{
@ManyToOne
private Artikel artikel;
Speeding up Java Persistence 11
Relationship Loading
Annahme:
Verwendet nur
AuftragsPosition
AuftragsPosition aufPos
= em.find(AuftragsPosition.class, id);
…
select …
from AuftragsPosition
where …
@ManyToOne
private Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY)
private Artikel artikel;
select … from AuftragsPosition where …
select … from Artikel where …
Speeding up Java Persistence 12
Relationship Loading
Annahme:
Verwendet auch
Artikel
AuftragsPosition aufPos
= em.find(AuftragsPosition.class, id);
…
Artikel artikel = aufPos.getArtikel();
…
@ManyToOne
private Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY)
private Artikel artikel;
select … from AuftragsPosition where …
select … from Artikel where …
select … from AuftragsPosition where …
…
select … from Artikel where …
Speeding up Java Persistence 13
Relationship Loading
Messergebnis (1000 Items, Hibernate, MySQL)
14Speeding up Java Persistence
EAGER LAZY
AuftragsPosition ohne Artikel 2.967 ms 2.505 ms - 15 %
AuftragsPosition mit Artikel 2.959 ms 4.305 ms + 45 %
Kunde ohne Auftrag 30.295 ms 4.848 ms - 84 %
=Default
Kunde Auftrag
Auftrags
Position
ArtikelLand
1 *
1
*
*
1
1*
Relationship Loading
Fazit:
Zugriffsverhalten genau analysieren
Default ist schon recht gut
Besser: Immer LAZY verwenden
und bei Bedarf Fetch Joins oder Entity Graphs nutzen
Speeding up Java Persistence 15
Relationship Loading
Fetch Joins
mit JPQL
Achtung: Kartesisches Produkt!
select ap from Auftragsposition ap
left join fetch ap.artikel
...
Speeding up Java Persistence 16
Relationship Loading
Fetch Joins
mit Criteria Query
CriteriaQuery<Auftrag> cQuery
= builder.createQuery(Auftrag.class);
Root<Auftrag> a = cQuery.from(Auftrag.class);
a.fetch(Auftrag_.auftragsPositionen, JoinType.LEFT)
.fetch(AuftragsPosition_.artikel, JoinType.LEFT);
…
Speeding up Java Persistence 17
Relationship Loading
Entity Graphs
@Entity
@NamedEntityGraph(
name = "Kunde.auftraege",
attributeNodes = @NamedAttributeNode(value = "auftraege")))
public class Kunde
{
@OneToMany(mappedBy="kunde")
private Set<Auftrag> auftraege;
TypedQuery<Kunde> query = entityManager.createQuery(…);
EntityGraph<?> entityGraph
= entityManager.getEntityGraph("Kunde.auftraege");
query.setHint("javax.persistence.loadgraph", entityGraph);
Speeding up Java Persistence 18
Fetch Tuning
ToMany-Fetching: "N+1"-Problem
z.B. Lesen einiger User inkl. Groups + Permissions
SELECT ... FROM USER
SELECT ... FROM GROUP WHERE USER_ID=?
SELECT ... FROM PERMISSION WHERE GROUP_ID=?
SELECT ... FROM PERMISSION WHERE GROUP_ID=?
SELECT ... FROM GROUP WHERE USER_ID=?
SELECT ... FROM GROUP WHERE USER_ID=?
Speeding up Java Persistence 19
Fetch Tuning
Lösungsansatz 1: Join Fetching
erzeugt 1 (!) SELECT
Achtung: Volumen!
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
Root<User> u = criteriaQuery.from(User.class);
u.fetch(User_.groups, JoinType.LEFT).fetch(Group_.permissions, JoinType.LEFT);
criteriaQuery.select(u).distinct(true);
List<User> users = entityManager.createQuery(criteriaQuery).getResultList();
Speeding up Java Persistence 20
Fetch Tuning
Lösungsansatz 2: Batch Fetching
@ManyToMany(fetch = FetchType.LAZY, …)
@BatchFetch(value = BatchFetchType.IN, size = 10)
private Set<Group> groups;
Annotation Relationsauflösung
EclipseLink @BatchFetch IN, EXISTS, JOIN
Hibernate @BatchSize IN, EXISTS
SELECT ... FROM USER
SELECT ... FROM GROUP WHERE USER_ID IN (?,?,…)
SELECT ... FROM PERMISSION WHERE GROUP_ID IN (?,?,…)
SELECT ... FROM PERMISSION WHERE GROUP_ID IN (?,?,…)
SELECT ... FROM GROUP WHERE USER_ID IN (?,?,…)
N+1
(N/B)+1
Speeding up Java Persistence 21
Basic Attribute Loading
Fetch-Strategie auch für einfache Werte wählbar
Lazy Loading ggf. sinnvoll bei
selten genutzten Werten
umfangreichen Daten
@Basic(fetch = FetchType.LAZY)
private String longAdditionalInfo;
Speeding up Java Persistence 22
Basic Attribute Loading
Messergebnis
Lesen von Kunden
10 'ungenutzte' Strings à 150 chars
1000 Interationen, Hibernate, MySQL
EAGER LAZY
6.782 ms 6.440 ms -5 %
= Default-Einstellung
Speeding up Java Persistence 23
Tupel-Selects
Selektion einzelner Attribute
als Tupel
mit Constructor Expression
Messergebnis (ms für 10000 Items)
select k.id, k.name from Kunde k
select new IdAndName(k.id, k.name) from Kunde k
Entity komplett Object[] Ctor Expression
11.211 ms 3.890 ms 4.010 ms
Speeding up Java Persistence 24
Query-Parameter
JPQL Injection
Prepared Statement Reuse
em.createQuery("select k from Kunde k "
+ "where k.name='" + someString + "'")
em.createQuery("select k from Kunde k "
+ "where k.name=:name")
.setParameter("name", someString)
Speeding up Java Persistence 25
Caching
JPA ProviderEntityManager
DB
2nd
Level
Cache
1st
Level
Cache
Query
Cache
Speeding up Java Persistence 26
First Level Cache
Standard
Je EntityManager
Enthält in Sitzung geladene Objekte
Achtung: Speicherbedarf!
sinnvolle EM-Lebensdauer nutzen
flush/clear ist i. A. Antipattern!
ausser im Batch – dort häufig sinnvoll
EntityManager
1st
Level
Cache
Speeding up Java Persistence 27
First Level Cache
Arbeitet
sitzungs-
bezogen
// Kunden mit bestimmter Id laden
EntityManager em1 = emf.createEntityManager();
Kunde k1 = em1.find(Kunde.class, id);
// Gleichen Kunden in 2. Session verändern
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
Kunde k2 = em2.find(Kunde.class, id);
k2.setName("…");
em2.getTransaction().commit();
// Gleichen Kunden in 1. Session erneut laden
Kunde k3 = em1.find(Kunde.class, id);
// ist unverändert!
Speeding up Java Persistence 28
First Level Cache
HashMap-Semantik
benötigt Key
wird für Queries nicht benutzt
// Kunden mit bestimmter Id laden
EntityManager em = emf.createEntityManager();
Kunde k1 = em.find(Kunde.class, id);
// Query nach gleichem Kunden geht erneut zur DB!
Kunde k2 = em.createQuery("select k from Kunde k " +
"where k.id=:id", Kunde.class)
.setParameter("id", id)
.getSingleResult();
Speeding up Java Persistence 29
Query Cache
Provider-spezifisch
Speichert Result Set IDs zu Queries
TypedQuery<Kunde> query
= em.createQuery("select k from Kunde k where k.name=:name",
Kunde.class);
query.setParameter("name", "OPQ GbR");
… // Query Cache einschalten
Kunde kunde = query.getSingleResult();
["select k from Kunde k where k.name=:name", "OPQ GbR"]  [id1]
Speeding up Java Persistence 30
Query Cache
Trotz mehrfacher Query
nur ein DB-Zugriff
while (…)
{
TypedQuery<Kunde> query
= em.createQuery("select k from Kunde k where k.name=:name",
Kunde.class);
query.setParameter("name", "OPQ GbR");
query.setHint(…) // Query Cache einschalten (providerabh.!)
Kunde kunde = query.getSingleResult();
…
}
Speeding up Java Persistence 31
Query Cache
EclipseLink:
Hibernate:
TypedQuery<Kunde> query = em.createQuery(…);
query.setHint("org.hibernate.cacheable", true);
…
TypedQuery<Kunde> query = em.createQuery(…);
query.setHint("eclipselink.cache-usage",
"CheckCacheThenDatabase");
…
Speeding up Java Persistence 32
Second Level Cache
JPA 2.x unterstützt 2nd Level Cache
nur rudimentäre Konfiguration
Providerspezifische
Konfiguration
in der Praxis
unabdingbar
JPA Provider
EntityManager
2nd
Level
Cache
1st
Level
Cache
Speeding up Java Persistence 33
Second Level Cache
Providerspezifische Implementierung
Cache-Provider
Infinispan, EHCache, OSCache, …
Cache-Strategien
read-only, read-write, …
Storage
Memory, Disk, Cluster, …
Speeding up Java Persistence 34
Second Level Cache
Wirkt applikationsweit
Semantik ähnlich HashMap
Ladereihenfolge:
1st Level Cache (EntityManager)
2nd Level Cache, falls enabled
DB
Speeding up Java Persistence 35
Second Level Cache
Vorteil bei häufig genutzten Daten
Konstanten
selten veränderte Daten
nur von dieser Anwendung veränderte Daten
Speeding up Java Persistence 36
Second Level Cache
Bsp.: Stammdaten-Entity Land
wird n:1 von Kunde
referenziert
nur wenige Land-Werte
Länder ändern sich nahezu nie
Länder können dauerhaft im Cache verbleiben
Kunde
Land
1
*
Speeding up Java Persistence 37
Second Level Cache
Konfiguration lt. Spec
<persistence-unit name="…">
<provider>…</provider>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
…
Cache aktiv für … Default bei …
ALL alle Entities
NONE keine Klasse Hibernate
ENABLE_SELECTIVE nur @Cacheable(true)
DISABLE_SELECTIVE alle außer @Cacheable(false) EclipseLink
@Entity
@Cacheable(true)
public class Land
{
…
Speeding up Java Persistence 38
Second Level Cache
Messergebnis
(1000 Interationen, Hibernate, MySQL)
ohne L2C: 8.975 ms
mit L2C für Land: 5.401 ms
Speeding up Java Persistence 39
Second Level Cache
L2C für Anwendungscode transparent
find liefert Kopie des Cache-Eintrags
Für komplett konstante Werte kann ein weiterer Cache in der
Anwendung sinnvoll sein
Speeding up Java Persistence 40
Paginierung
Queries mit großer Ergebnismenge
'häppchenweise' verarbeiten
TypedQuery<Artikel> query
= em.createQuery("select a from Artikel a", Artikel.class);
query.setFirstResult(50);
query.setMaxResults(10);
List<Artikel> result = query.getResultList();
select …
from Artikel
where … and rownum>=50 and rownum<60
Speeding up Java Persistence 41
Paginierung
Eingeschränkt oder effektlos bei 1:n/m:n-Relationen mit:
Eager Loading
Fetch Joins
Join erzeugt kartesisches Produkt
Providerabhängige Lösung:
Ausführung im Memory
Ausführung mehrerer SQL-Befehle
Speeding up Java Persistence 42
Inheritance
Mehrere Abbildungen denkbar:
Alles in einer Tabelle
Eine Tabelle pro Klasse
Eine Tabelle pro konkreter Klasse
Strategie-Auswahl mit @Inheritance
<abstract>
Vehicle
Car Ship
Speeding up Java Persistence 43
Inheritance
SINGLE_TABLE
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Vehicle
{
…
Speeding up Java Persistence 44
Inheritance
JOINED
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Vehicle
{
…
Speeding up Java Persistence 45
Inheritance
TABLE_PER_CLASS
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle
{
…
Speeding up Java Persistence 46
Inheritance
Laufzeitvergleich für Queries
auf Basisklasse
auf abgeleitete Klasse
(1000 Iterationen, Ergebnis ca. 100 Einträge, Hibernate, MySQL)
SINGLE_
TABLE
TABLE_
PER_CLASS
JOINED
Basisklasse 2.705 ms 29.359 ms 3.434 ms
Subklasse 2.505 ms 1.435 ms 3.377 ms
Speeding up Java Persistence 47
Inheritance
Optimale Performanz liefern
SINGLE_TABLE und TABLE_PER_CLASS
Aber: Auch andere Implikationen
Genaue Analyse notwendig
Speeding up Java Persistence 48
Wenn‘s dennoch nicht reicht
Native Queries
Stored Procedure Queries
User Functions
Speeding up Java Persistence 49
Fazit
Viele Optimierungen providerunabhängig möglich
Wesentlich:
Lazy Loading
Caching
Genaue Analyse notwendig
Messen
Kein Selbstzweck
Speeding up Java Persistence 50
More
http://www.gedoplan-it-training.de
Seminare in Berlin, Bielefeld, Inhouse
http://www.gedoplan-it-consulting.de
Reviews, Coaching, …
http://javaeeblog.wordpress.com/
http://expertenkreisjava.blogspot.de/
 dirk.weil@gedoplan.de
@dirkweil
Speeding up Java Persistence 51

Weitere ähnliche Inhalte

Was ist angesagt?

Auszug Seminarmaterial "EJB 3.x"
Auszug Seminarmaterial "EJB 3.x"Auszug Seminarmaterial "EJB 3.x"
Auszug Seminarmaterial "EJB 3.x"
schellsoft
 
MongoDB - Riesige Datenmengen schemafrei verwalten
MongoDB - Riesige Datenmengen schemafrei verwaltenMongoDB - Riesige Datenmengen schemafrei verwalten
MongoDB - Riesige Datenmengen schemafrei verwalten
Tobias Trelle
 
Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)
Michael Romer
 
130605 blog - drools
130605   blog - drools130605   blog - drools
130605 blog - drools
java-pe
 

Was ist angesagt? (16)

Query Result Caching
Query Result CachingQuery Result Caching
Query Result Caching
 
Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!Testen im EE-Umfeld – Seien Sie feige!
Testen im EE-Umfeld – Seien Sie feige!
 
Go Fullstack: Webanwendungen mit Java EE 6 bauen (W-JAX 2011)
Go Fullstack: Webanwendungen mit Java EE 6 bauen (W-JAX 2011)Go Fullstack: Webanwendungen mit Java EE 6 bauen (W-JAX 2011)
Go Fullstack: Webanwendungen mit Java EE 6 bauen (W-JAX 2011)
 
Regelbasierte Systeme mit JBoss Drools
Regelbasierte Systeme mit JBoss DroolsRegelbasierte Systeme mit JBoss Drools
Regelbasierte Systeme mit JBoss Drools
 
Entity framework
Entity frameworkEntity framework
Entity framework
 
Auszug Seminarmaterial "EJB 3.x"
Auszug Seminarmaterial "EJB 3.x"Auszug Seminarmaterial "EJB 3.x"
Auszug Seminarmaterial "EJB 3.x"
 
Datenbankoptimierung
DatenbankoptimierungDatenbankoptimierung
Datenbankoptimierung
 
MongoDB - Riesige Datenmengen schemafrei verwalten
MongoDB - Riesige Datenmengen schemafrei verwaltenMongoDB - Riesige Datenmengen schemafrei verwalten
MongoDB - Riesige Datenmengen schemafrei verwalten
 
JSF und JPA effizient kombinieren (W-JAX 2011)
JSF und JPA effizient kombinieren (W-JAX 2011)JSF und JPA effizient kombinieren (W-JAX 2011)
JSF und JPA effizient kombinieren (W-JAX 2011)
 
Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)
 
SOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter SystemeSOLID Prinzipien, Designgrundlagen objektorientierter Systeme
SOLID Prinzipien, Designgrundlagen objektorientierter Systeme
 
AdvancedTdd
AdvancedTddAdvancedTdd
AdvancedTdd
 
Java EE 5
Java EE 5Java EE 5
Java EE 5
 
Wie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
Wie skaliert man Software as a Service Applikationen in der Windows Azure CloudWie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
Wie skaliert man Software as a Service Applikationen in der Windows Azure Cloud
 
Drohnen und WARP-Antriebe
Drohnen und WARP-AntriebeDrohnen und WARP-Antriebe
Drohnen und WARP-Antriebe
 
130605 blog - drools
130605   blog - drools130605   blog - drools
130605 blog - drools
 

Andere mochten auch

Jpa queries
Jpa queriesJpa queries
Jpa queries
gedoplan
 

Andere mochten auch (14)

Java EE 7 - Enterprise-Anwendungen ohne Ballast
Java EE 7 - Enterprise-Anwendungen ohne BallastJava EE 7 - Enterprise-Anwendungen ohne Ballast
Java EE 7 - Enterprise-Anwendungen ohne Ballast
 
Versionierung mit GIT
Versionierung mit GITVersionierung mit GIT
Versionierung mit GIT
 
Leichtgewichtige Microservices mit Java EE 7
Leichtgewichtige Microservices mit Java EE 7Leichtgewichtige Microservices mit Java EE 7
Leichtgewichtige Microservices mit Java EE 7
 
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevelsjavaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
 
WildFly als Plattform moderner Enterprise-Anwendungen
WildFly als Plattform moderner Enterprise-AnwendungenWildFly als Plattform moderner Enterprise-Anwendungen
WildFly als Plattform moderner Enterprise-Anwendungen
 
Speeding up Java Persistence
Speeding up Java PersistenceSpeeding up Java Persistence
Speeding up Java Persistence
 
Infinispan / JBoss Data Grid - Schneller Zugriff auf große Datenmengen im Cl...
 Infinispan / JBoss Data Grid - Schneller Zugriff auf große Datenmengen im Cl... Infinispan / JBoss Data Grid - Schneller Zugriff auf große Datenmengen im Cl...
Infinispan / JBoss Data Grid - Schneller Zugriff auf große Datenmengen im Cl...
 
Jpa queries
Jpa queriesJpa queries
Jpa queries
 
Macit Kandemir, Flexible Datenbank-Anwendungen mit MongoDB
Macit Kandemir, Flexible Datenbank-Anwendungen mit MongoDBMacit Kandemir, Flexible Datenbank-Anwendungen mit MongoDB
Macit Kandemir, Flexible Datenbank-Anwendungen mit MongoDB
 
Java EE 7 - Enterprise-Anwendungen ohne Ballast
Java EE 7 - Enterprise-Anwendungen ohne BallastJava EE 7 - Enterprise-Anwendungen ohne Ballast
Java EE 7 - Enterprise-Anwendungen ohne Ballast
 
Apache camel
Apache camelApache camel
Apache camel
 
Java Batch – Der Standard für's Stapeln
Java Batch – Der Standard für's StapelnJava Batch – Der Standard für's Stapeln
Java Batch – Der Standard für's Stapeln
 
AngularJS
AngularJSAngularJS
AngularJS
 
Wie viel Client braucht das Web?JSF, Vaadin und AngularJS im Vergleich
Wie viel Client braucht das Web?JSF, Vaadin und AngularJS im VergleichWie viel Client braucht das Web?JSF, Vaadin und AngularJS im Vergleich
Wie viel Client braucht das Web?JSF, Vaadin und AngularJS im Vergleich
 

Ähnlich wie Speeding up Java Persistence

Datenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence ApiDatenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence Api
Christian Baranowski
 
Lightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPALightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPA
mh0708
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Way
jubecker
 
Fanstatic pycon.de 2012
Fanstatic pycon.de 2012Fanstatic pycon.de 2012
Fanstatic pycon.de 2012
Daniel Havlik
 
Celery eine asynchrone task queue (nicht nur) für django
Celery   eine asynchrone task queue (nicht nur) für djangoCelery   eine asynchrone task queue (nicht nur) für django
Celery eine asynchrone task queue (nicht nur) für django
Markus Zapke-Gründemann
 

Ähnlich wie Speeding up Java Persistence (20)

Datenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence ApiDatenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence Api
 
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
 
Feige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-UmfeldFeige sein! Testen im Java-EE-Umfeld
Feige sein! Testen im Java-EE-Umfeld
 
DB-Schema-Evolution mit LiquiBase
DB-Schema-Evolution mit LiquiBaseDB-Schema-Evolution mit LiquiBase
DB-Schema-Evolution mit LiquiBase
 
Lightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPALightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPA
 
Enterprise Java Batch mit Spring
Enterprise Java Batch mit SpringEnterprise Java Batch mit Spring
Enterprise Java Batch mit Spring
 
Workshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GAWorkshop zu Hibernate 3.2.2 GA
Workshop zu Hibernate 3.2.2 GA
 
JEE-Microservices mit Quarkus – eine Einführung
JEE-Microservices mit Quarkus – eine EinführungJEE-Microservices mit Quarkus – eine Einführung
JEE-Microservices mit Quarkus – eine Einführung
 
Elegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2day
Elegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2dayElegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2day
Elegantes In-Memory Computing mit Apache Ignite und Kubernetes. @data2day
 
In-Memory Computing mit Apache Ignite und Kubernetes
In-Memory Computing mit Apache Ignite und KubernetesIn-Memory Computing mit Apache Ignite und Kubernetes
In-Memory Computing mit Apache Ignite und Kubernetes
 
Wordpress on steroids
Wordpress on steroidsWordpress on steroids
Wordpress on steroids
 
Hands-on Hystrix - Best Practices und Stolperfallen
Hands-on Hystrix - Best Practices und StolperfallenHands-on Hystrix - Best Practices und Stolperfallen
Hands-on Hystrix - Best Practices und Stolperfallen
 
Celery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoCelery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für Django
 
Praesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit ExtbasePraesentation TYPO3Camp Berlin Speed mit Extbase
Praesentation TYPO3Camp Berlin Speed mit Extbase
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Way
 
Fanstatic pycon.de 2012
Fanstatic pycon.de 2012Fanstatic pycon.de 2012
Fanstatic pycon.de 2012
 
Celery eine asynchrone task queue (nicht nur) für django
Celery   eine asynchrone task queue (nicht nur) für djangoCelery   eine asynchrone task queue (nicht nur) für django
Celery eine asynchrone task queue (nicht nur) für django
 
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
Das Runde muss in das Eckige - Java-Anwendungen für Kubernetes entwickeln und...
 
Legacy Code refaktorisieren
Legacy Code refaktorisierenLegacy Code refaktorisieren
Legacy Code refaktorisieren
 

Speeding up Java Persistence

  • 1. Speeding up Java Persistence Dirk Weil, GEDOPLAN GmbH
  • 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Seminare Vorträge Veröffentlichungen Speeding up Java Persistence 2
  • 3. Id-Generierung Entity-Klassen müssen Id haben PK in der DB Feld oder Property mit @Id Empfehlenswert: Technische Id Problem: Erzeugung eindeutiger Werte @Entity public class SomeEntity { @Id private int id; … Speeding up Java Persistence 3
  • 4. Id-Generierung JPA-Feature: @GeneratedValue Nutzt DB-Sequenzen, Identity Columns oder Sequenz-Tabellen Probleme: Id erst nach persist gesetzt  equals?, hashCode? Id-Übernahme kostet Zeit @Id @GeneratedValue private int id; Speeding up Java Persistence 4
  • 5. Id-Generierung Alternative: BYO-ID (selbst machen) Id auch in transitiven Objekten gesetzt Insert ohne Zusatzaufwand Achtung: i. A. nicht trivial Z. B.: UUID this.id = UUID.randomUUID().toString(); // oder: new com.eaio.uuid.UUID().toString() Speeding up Java Persistence 5
  • 7. Id-Generierung Tuning: Höhere Allocation Size Leider nicht verfügbar bei IDENTITY @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ArtikelIdGenerator") @SequenceGenerator(name = "ArtikelIdGenerator", allocationSize = 1000) private int id;@Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "ArtikelIdGenerator") @TableGenerator(name = "ArtikelIdGenerator", allocationSize = 1000) private int id; Speeding up Java Persistence 7
  • 9. Relationship Loading Relationen werden durch Attribute mit @…To… repräsentiert @Entity public class Book { @ManyToOne public Publisher publisher; @Entity public class Publisher { @OneToMany(mappedBy="publisher") public List<Book> books; Speeding up Java Persistence 9
  • 10. Relationship Loading Relationen-Parameter: fetch Referenzierte Entities direkt laden? EAGER: Direkt LAZY: Später bei Bedarf @ManyToOne(fetch = FetchType.LAZY) private Artikel artikel; Speeding up Java Persistence 10
  • 11. Relationship Loading Bsp.: Auftragsposition bearbeiten n:1-Relation zu Artikel Kunde Auftrag Auftrags Position ArtikelLand 1 * 1 * * 1 1* @Entity public class AuftragsPosition { @ManyToOne private Artikel artikel; Speeding up Java Persistence 11
  • 12. Relationship Loading Annahme: Verwendet nur AuftragsPosition AuftragsPosition aufPos = em.find(AuftragsPosition.class, id); … select … from AuftragsPosition where … @ManyToOne private Artikel artikel; @ManyToOne(fetch=FetchType.LAZY) private Artikel artikel; select … from AuftragsPosition where … select … from Artikel where … Speeding up Java Persistence 12
  • 13. Relationship Loading Annahme: Verwendet auch Artikel AuftragsPosition aufPos = em.find(AuftragsPosition.class, id); … Artikel artikel = aufPos.getArtikel(); … @ManyToOne private Artikel artikel; @ManyToOne(fetch=FetchType.LAZY) private Artikel artikel; select … from AuftragsPosition where … select … from Artikel where … select … from AuftragsPosition where … … select … from Artikel where … Speeding up Java Persistence 13
  • 14. Relationship Loading Messergebnis (1000 Items, Hibernate, MySQL) 14Speeding up Java Persistence EAGER LAZY AuftragsPosition ohne Artikel 2.967 ms 2.505 ms - 15 % AuftragsPosition mit Artikel 2.959 ms 4.305 ms + 45 % Kunde ohne Auftrag 30.295 ms 4.848 ms - 84 % =Default Kunde Auftrag Auftrags Position ArtikelLand 1 * 1 * * 1 1*
  • 15. Relationship Loading Fazit: Zugriffsverhalten genau analysieren Default ist schon recht gut Besser: Immer LAZY verwenden und bei Bedarf Fetch Joins oder Entity Graphs nutzen Speeding up Java Persistence 15
  • 16. Relationship Loading Fetch Joins mit JPQL Achtung: Kartesisches Produkt! select ap from Auftragsposition ap left join fetch ap.artikel ... Speeding up Java Persistence 16
  • 17. Relationship Loading Fetch Joins mit Criteria Query CriteriaQuery<Auftrag> cQuery = builder.createQuery(Auftrag.class); Root<Auftrag> a = cQuery.from(Auftrag.class); a.fetch(Auftrag_.auftragsPositionen, JoinType.LEFT) .fetch(AuftragsPosition_.artikel, JoinType.LEFT); … Speeding up Java Persistence 17
  • 18. Relationship Loading Entity Graphs @Entity @NamedEntityGraph( name = "Kunde.auftraege", attributeNodes = @NamedAttributeNode(value = "auftraege"))) public class Kunde { @OneToMany(mappedBy="kunde") private Set<Auftrag> auftraege; TypedQuery<Kunde> query = entityManager.createQuery(…); EntityGraph<?> entityGraph = entityManager.getEntityGraph("Kunde.auftraege"); query.setHint("javax.persistence.loadgraph", entityGraph); Speeding up Java Persistence 18
  • 19. Fetch Tuning ToMany-Fetching: "N+1"-Problem z.B. Lesen einiger User inkl. Groups + Permissions SELECT ... FROM USER SELECT ... FROM GROUP WHERE USER_ID=? SELECT ... FROM PERMISSION WHERE GROUP_ID=? SELECT ... FROM PERMISSION WHERE GROUP_ID=? SELECT ... FROM GROUP WHERE USER_ID=? SELECT ... FROM GROUP WHERE USER_ID=? Speeding up Java Persistence 19
  • 20. Fetch Tuning Lösungsansatz 1: Join Fetching erzeugt 1 (!) SELECT Achtung: Volumen! CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); Root<User> u = criteriaQuery.from(User.class); u.fetch(User_.groups, JoinType.LEFT).fetch(Group_.permissions, JoinType.LEFT); criteriaQuery.select(u).distinct(true); List<User> users = entityManager.createQuery(criteriaQuery).getResultList(); Speeding up Java Persistence 20
  • 21. Fetch Tuning Lösungsansatz 2: Batch Fetching @ManyToMany(fetch = FetchType.LAZY, …) @BatchFetch(value = BatchFetchType.IN, size = 10) private Set<Group> groups; Annotation Relationsauflösung EclipseLink @BatchFetch IN, EXISTS, JOIN Hibernate @BatchSize IN, EXISTS SELECT ... FROM USER SELECT ... FROM GROUP WHERE USER_ID IN (?,?,…) SELECT ... FROM PERMISSION WHERE GROUP_ID IN (?,?,…) SELECT ... FROM PERMISSION WHERE GROUP_ID IN (?,?,…) SELECT ... FROM GROUP WHERE USER_ID IN (?,?,…) N+1 (N/B)+1 Speeding up Java Persistence 21
  • 22. Basic Attribute Loading Fetch-Strategie auch für einfache Werte wählbar Lazy Loading ggf. sinnvoll bei selten genutzten Werten umfangreichen Daten @Basic(fetch = FetchType.LAZY) private String longAdditionalInfo; Speeding up Java Persistence 22
  • 23. Basic Attribute Loading Messergebnis Lesen von Kunden 10 'ungenutzte' Strings à 150 chars 1000 Interationen, Hibernate, MySQL EAGER LAZY 6.782 ms 6.440 ms -5 % = Default-Einstellung Speeding up Java Persistence 23
  • 24. Tupel-Selects Selektion einzelner Attribute als Tupel mit Constructor Expression Messergebnis (ms für 10000 Items) select k.id, k.name from Kunde k select new IdAndName(k.id, k.name) from Kunde k Entity komplett Object[] Ctor Expression 11.211 ms 3.890 ms 4.010 ms Speeding up Java Persistence 24
  • 25. Query-Parameter JPQL Injection Prepared Statement Reuse em.createQuery("select k from Kunde k " + "where k.name='" + someString + "'") em.createQuery("select k from Kunde k " + "where k.name=:name") .setParameter("name", someString) Speeding up Java Persistence 25
  • 27. First Level Cache Standard Je EntityManager Enthält in Sitzung geladene Objekte Achtung: Speicherbedarf! sinnvolle EM-Lebensdauer nutzen flush/clear ist i. A. Antipattern! ausser im Batch – dort häufig sinnvoll EntityManager 1st Level Cache Speeding up Java Persistence 27
  • 28. First Level Cache Arbeitet sitzungs- bezogen // Kunden mit bestimmter Id laden EntityManager em1 = emf.createEntityManager(); Kunde k1 = em1.find(Kunde.class, id); // Gleichen Kunden in 2. Session verändern EntityManager em2 = emf.createEntityManager(); em2.getTransaction().begin(); Kunde k2 = em2.find(Kunde.class, id); k2.setName("…"); em2.getTransaction().commit(); // Gleichen Kunden in 1. Session erneut laden Kunde k3 = em1.find(Kunde.class, id); // ist unverändert! Speeding up Java Persistence 28
  • 29. First Level Cache HashMap-Semantik benötigt Key wird für Queries nicht benutzt // Kunden mit bestimmter Id laden EntityManager em = emf.createEntityManager(); Kunde k1 = em.find(Kunde.class, id); // Query nach gleichem Kunden geht erneut zur DB! Kunde k2 = em.createQuery("select k from Kunde k " + "where k.id=:id", Kunde.class) .setParameter("id", id) .getSingleResult(); Speeding up Java Persistence 29
  • 30. Query Cache Provider-spezifisch Speichert Result Set IDs zu Queries TypedQuery<Kunde> query = em.createQuery("select k from Kunde k where k.name=:name", Kunde.class); query.setParameter("name", "OPQ GbR"); … // Query Cache einschalten Kunde kunde = query.getSingleResult(); ["select k from Kunde k where k.name=:name", "OPQ GbR"]  [id1] Speeding up Java Persistence 30
  • 31. Query Cache Trotz mehrfacher Query nur ein DB-Zugriff while (…) { TypedQuery<Kunde> query = em.createQuery("select k from Kunde k where k.name=:name", Kunde.class); query.setParameter("name", "OPQ GbR"); query.setHint(…) // Query Cache einschalten (providerabh.!) Kunde kunde = query.getSingleResult(); … } Speeding up Java Persistence 31
  • 32. Query Cache EclipseLink: Hibernate: TypedQuery<Kunde> query = em.createQuery(…); query.setHint("org.hibernate.cacheable", true); … TypedQuery<Kunde> query = em.createQuery(…); query.setHint("eclipselink.cache-usage", "CheckCacheThenDatabase"); … Speeding up Java Persistence 32
  • 33. Second Level Cache JPA 2.x unterstützt 2nd Level Cache nur rudimentäre Konfiguration Providerspezifische Konfiguration in der Praxis unabdingbar JPA Provider EntityManager 2nd Level Cache 1st Level Cache Speeding up Java Persistence 33
  • 34. Second Level Cache Providerspezifische Implementierung Cache-Provider Infinispan, EHCache, OSCache, … Cache-Strategien read-only, read-write, … Storage Memory, Disk, Cluster, … Speeding up Java Persistence 34
  • 35. Second Level Cache Wirkt applikationsweit Semantik ähnlich HashMap Ladereihenfolge: 1st Level Cache (EntityManager) 2nd Level Cache, falls enabled DB Speeding up Java Persistence 35
  • 36. Second Level Cache Vorteil bei häufig genutzten Daten Konstanten selten veränderte Daten nur von dieser Anwendung veränderte Daten Speeding up Java Persistence 36
  • 37. Second Level Cache Bsp.: Stammdaten-Entity Land wird n:1 von Kunde referenziert nur wenige Land-Werte Länder ändern sich nahezu nie Länder können dauerhaft im Cache verbleiben Kunde Land 1 * Speeding up Java Persistence 37
  • 38. Second Level Cache Konfiguration lt. Spec <persistence-unit name="…"> <provider>…</provider> <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> … Cache aktiv für … Default bei … ALL alle Entities NONE keine Klasse Hibernate ENABLE_SELECTIVE nur @Cacheable(true) DISABLE_SELECTIVE alle außer @Cacheable(false) EclipseLink @Entity @Cacheable(true) public class Land { … Speeding up Java Persistence 38
  • 39. Second Level Cache Messergebnis (1000 Interationen, Hibernate, MySQL) ohne L2C: 8.975 ms mit L2C für Land: 5.401 ms Speeding up Java Persistence 39
  • 40. Second Level Cache L2C für Anwendungscode transparent find liefert Kopie des Cache-Eintrags Für komplett konstante Werte kann ein weiterer Cache in der Anwendung sinnvoll sein Speeding up Java Persistence 40
  • 41. Paginierung Queries mit großer Ergebnismenge 'häppchenweise' verarbeiten TypedQuery<Artikel> query = em.createQuery("select a from Artikel a", Artikel.class); query.setFirstResult(50); query.setMaxResults(10); List<Artikel> result = query.getResultList(); select … from Artikel where … and rownum>=50 and rownum<60 Speeding up Java Persistence 41
  • 42. Paginierung Eingeschränkt oder effektlos bei 1:n/m:n-Relationen mit: Eager Loading Fetch Joins Join erzeugt kartesisches Produkt Providerabhängige Lösung: Ausführung im Memory Ausführung mehrerer SQL-Befehle Speeding up Java Persistence 42
  • 43. Inheritance Mehrere Abbildungen denkbar: Alles in einer Tabelle Eine Tabelle pro Klasse Eine Tabelle pro konkreter Klasse Strategie-Auswahl mit @Inheritance <abstract> Vehicle Car Ship Speeding up Java Persistence 43
  • 47. Inheritance Laufzeitvergleich für Queries auf Basisklasse auf abgeleitete Klasse (1000 Iterationen, Ergebnis ca. 100 Einträge, Hibernate, MySQL) SINGLE_ TABLE TABLE_ PER_CLASS JOINED Basisklasse 2.705 ms 29.359 ms 3.434 ms Subklasse 2.505 ms 1.435 ms 3.377 ms Speeding up Java Persistence 47
  • 48. Inheritance Optimale Performanz liefern SINGLE_TABLE und TABLE_PER_CLASS Aber: Auch andere Implikationen Genaue Analyse notwendig Speeding up Java Persistence 48
  • 49. Wenn‘s dennoch nicht reicht Native Queries Stored Procedure Queries User Functions Speeding up Java Persistence 49
  • 50. Fazit Viele Optimierungen providerunabhängig möglich Wesentlich: Lazy Loading Caching Genaue Analyse notwendig Messen Kein Selbstzweck Speeding up Java Persistence 50
  • 51. More http://www.gedoplan-it-training.de Seminare in Berlin, Bielefeld, Inhouse http://www.gedoplan-it-consulting.de Reviews, Coaching, … http://javaeeblog.wordpress.com/ http://expertenkreisjava.blogspot.de/  dirk.weil@gedoplan.de @dirkweil Speeding up Java Persistence 51