SlideShare ist ein Scribd-Unternehmen logo
1 von 54
Downloaden Sie, um offline zu lesen
Optimierung von JPA-Anwendungen
Dirk Weil, GEDOPLAN GmbH
Dirk Weil
GEDOPLAN GmbH, Bielefeld
Java EE seit 1998
Konzeption und
Realisierung
Vorträge
Seminare
Veröffentlichungen
Optimierung von JPA-Anwendungen 2
Optimierung von JPA-Anwendungen
Laufzeit
Memory
Providerunabhängig
EclipseLink
Hibernate
…
Optimierung von JPA-Anwendungen 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;
…
Optimierung von JPA-Anwendungen 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;
Optimierung von JPA-Anwendungen 5
Id-Generierung
Alternative: BYO-ID (selbst machen, i. a. im Konstruktor)
Id auch in transitiven Objekten gesetzt
Insert ohne Zusatzaufwand
Achtung: i. A. nicht trivial
Z. B.: UUID
@Id
private String id
= new com.eaio.uuid.UUID().toString();
Optimierung von JPA-Anwendungen 6
Id-Generierung
@GeneratedValue signifikant langsamer
(OOTB)
Derby
EclipseLink
MySQL
EclipseLink
Oracle
EclipseLink
Derby
Hibernate
MySQL
Hibernate
Oracle
Hibernate
BYO-ID 19.864 11.659 22.478 19.240 9.684 7.126
AUTO 21.034 13.537 23.663 74.804 12.214 70.814
0
10.000
20.000
30.000
40.000
50.000
60.000
70.000
80.000
Millisekunden
Insert 50.000 einfache Entries
in 1.000er Batches
Optimierung von JPA-Anwendungen 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;
Optimierung von JPA-Anwendungen 8
Id-Generierung
0
10.000
20.000
30.000
40.000
50.000
60.000
70.000
80.000
1 10 100 1000
Laufzeit vs. Allocation Size
Optimierung von JPA-Anwendungen 9
Relationship Loading
Relationen werden durch Felder mit @OneToOne, …,
@ManyToMany repräsentiert
@Entity
public class Book
{
@ManyToOne
public Publisher publisher;
@Entity
public class Publisher
{
@OneToMany(mappedBy="publisher")
public List<Book> books;
Optimierung von JPA-Anwendungen 10
Relationship Loading
Relationen-Parameter: fetch
Referenzierte Entities direkt laden?
EAGER: Direkt
LAZY: Später bei Bedarf
@ManyToOne(fetch = FetchType.LAZY)
private Artikel artikel;
Optimierung von JPA-Anwendungen 11
Relationship Loading
Bsp.: Auftragsposition bearbeiten
Ist Owner der n:1-Relation zu Artikel
Kunde Auftrag
Auftrags
Position
ArtikelLand
1 *
1
*
*
1
1*
@Entity
public class AuftragsPosition
{
@ManyToOne
private Artikel artikel;
Optimierung von JPA-Anwendungen 12
Relationship Loading
Annahme:
Verwendet nur
AuftragsPosition
AuftragsPosition aufPos
= em.find(AuftragsPosition.class, id);
…
select …
from AuftragsPosition
where …
select …
from AuftragsPosition
left outer join Artikel
where …
@ManyToOne
private Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY)
private Artikel artikel;
Optimierung von JPA-Anwendungen 13
Relationship Loading
Annahme:
Verwendet auch
Artikel
AuftragsPosition aufPos
= em.find(AuftragsPosition.class, id);
Artikel artikel = aufPos.getArtikel();
…
select … from AuftragsPosition where …
select … from Artikel where …
select …
from AuftragsPosition
left outer join Artikel
where …
@ManyToOne
private Artikel artikel;
@ManyToOne(fetch=FetchType.LAZY)
private Artikel artikel;
Optimierung von JPA-Anwendungen 14
Relationship Loading
Bsp.: Kunde bearbeiten
Ist Owner der 1:n-Relation zu Auftrag
Kunde Auftrag
Auftrags
Position
ArtikelLand
1 *
1
*
*
1
1*
@Entity
public class Kunde
{
@OneToMany(mappedBy="kunde")
private Set<Auftrag> auftraege;
Optimierung von JPA-Anwendungen 15
Relationship Loading
Annahme:
Verwendet
nur Kunde
Kunde kunde
= em.find(Kunde.class, id);…
select …
from Kunde
where …
select …
from Kunde
left outer join Auftrag
left outer join AuftragsPosition
where …
@ManyToOne(fetch=FetchType.EAGER)
private Set<Auftrag> auftraege;
@ManyToOne
private Set<Auftrag> auftraege;
Optimierung von JPA-Anwendungen 16
Relationship Loading
Messergebnis
(1000 Interationen, Hibernate, MySQL)
EAGER LAZY
Nur AuftragsPosition 2.967 ms 2.505 ms - 15 %
Auch Artikel 2.959 ms 4.305 ms + 45 %
Nur Kunde 30.295 ms 4.848 ms - 84 %
= Default-Einstellung
Optimierung von JPA-Anwendungen 17
Relationship Loading
Fazit:
Zugriffsverhalten genau analysieren
Default ist schon recht gut
Besser: Immer LAZY verwenden und bei Bedarf nachladen
providerspezifische Mittel
left join fetch
Load/Fetch Graph (ab JPA 2.1)
Optimierung von JPA-Anwendungen 18
Relationship Loading
Fetch Joins mit JPQL
leider nur einstufig erlaubt
select ap from Auftragsposition ap
left join fetch ap.artikel
...
Optimierung von JPA-Anwendungen 19
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)
.fetch(AuftragsPosition_.artikel);
…
Optimierung von JPA-Anwendungen 20
Fetch Tuning
ToMany-Fetching: "N+1"-Problem
z.B. Lesen der User inkl. Groups + Permissions
SELECT ... FROM USER
SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND …
SELECT ... FROM PERMISSION WHERE GROUP_ID=?
SELECT ... FROM PERMISSION WHERE GROUP_ID=?
SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND …
SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND …
Optimierung von JPA-Anwendungen 21
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();
Optimierung von JPA-Anwendungen 22
Fetch Tuning
Lösungsansatz 2: Batch Fetching
erzeugt 1 SELECT pro 'Ebene'
@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
OpenJPA @EagerFetchMode
(nur für EAGER!)
JOIN
(='PARALLEL')
Optimierung von JPA-Anwendungen 23
Basic Attribute Loading
Fetch-Strategie auch für einfache Werte wählbar
Lazy Loading sinnvoll bei
selten genutzten Werten
umfangreichen Daten
@Basic(fetch = FetchType.LAZY)
private String longAdditionalInfo;
Optimierung von JPA-Anwendungen 24
Basic Attribute Loading
Messergebnis
Lesen von Kunden
10 'ungenutzte' Strings à 150 chars
1000 Interationen, EclipseLink, Oracle
EAGER LAZY
7.204 ms 6.820 ms -5 %
= Default-Einstellung
Optimierung von JPA-Anwendungen 25
Lazy-Load-Verfahren
Proxy
@OneToMany
private Set<Auftrag> auftraege
get(…)
?
DB
Optimierung von JPA-Anwendungen 26
Lazy-Load-Verfahren
Instrumentierung
@Basic(fetch = FetchType.LAZY)
private String longAdditionalInfo;
get(…)
?
DB
Optimierung von JPA-Anwendungen 27
Bytecode-Instrumentierung
 = Standard
 = Providerspezifische Konfiguration erforderlich
Eclipselink
Verfahren SE EE
@Basic Entity Instrumentation  
@xxxToOne Entity Instrumentation  
@xxxToMany Collection Proxy  
Hibernate
Verfahren SE EE
@Basic Entity Instrumentation  
@xxxToOne Attribute Proxy  
@xxxToMany Collection Proxy  
Optimierung von JPA-Anwendungen 28
JPA Provider
Caching
EntityManager
DB
2nd
Level
Cache
1st
Level
Cache
Query
Cache
Optimierung von JPA-Anwendungen 29
First Level Cache
Standard
Je EntityManager
Enthält in Sitzung geladene Objekte
Achtung: Speicherbedarf!
ggf. explizit entlasten (clear, detach)
EntityManager
1st
Level
Cache
Optimierung von JPA-Anwendungen 30
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!
Optimierung von JPA-Anwendungen 31
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();
Optimierung von JPA-Anwendungen 32
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]
Optimierung von JPA-Anwendungen 33
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();
…
}
Optimierung von JPA-Anwendungen 34
Query Cache
EclipseLink
Hibernate:
(Aktivierung in der Konfiguration notwendig)
TypedQuery<Kunde> query = em.createQuery(…);
query.setHint("org.hibernate.cacheable", true);
…
TypedQuery<Kunde> query = em.createQuery(…);
query.setHint("eclipselink.cache-usage",
"CheckCacheThenDatabase");
…
Optimierung von JPA-Anwendungen 35
Second Level Cache
JPA 2.0 unterstützt 2nd Level Cache
nur rudimentäre Konfiguration
Providerspezifische
Konfiguration
in der Praxis
unabdingbar JPA Provider
EntityManager
2nd
Level
Cache
1st
Level
Cache
Optimierung von JPA-Anwendungen 36
Second Level Cache
Providerspezifische Implementierung
Cache-Provider
Infinispan, EHCache, OSCache, …
Cache-Strategien
read-only, read-write, …
Storage
Memory, Disk, Cluster, …
Optimierung von JPA-Anwendungen 37
Second Level Cache
Wirkt applikationsweit
Semantik ähnlich HashMap
Ladereihenfolge:
1st Level Cache (EntityManager)
2nd Level Cache, falls enabled
DB
Optimierung von JPA-Anwendungen 38
Second Level Cache
Vorteil bei häufig genutzten Daten
Konstanten
selten veränderte Daten
nur von dieser Anwendung veränderte Daten
Optimierung von JPA-Anwendungen 39
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
*
Optimierung von JPA-Anwendungen 40
Second Level Cache
Konfiguration lt. Spec
<persistence-unit name="…">
<provider>…</provider>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
…
Cache aktiv für …
ALL alle Entities
NONE keine Klasse
ENABLE_SELECTIVE nur @Cacheable(true)
DISABLE_SELECTIVE alle außer @Cacheable(false)
@Entity
@Cacheable(true)
public class Land
{
…
Optimierung von JPA-Anwendungen 41
Second Level Cache
EclipseLink
Default: DISABLE_SELECTIVE
Hibernate bis Version 3.x
ignoriert Standard-Konfig
benötigt eigene Annotation
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Land
{
…
Optimierung von JPA-Anwendungen 42
Second Level Cache
Messergebnis
(1000 Interationen, EclipseLink, Oracle)
ohne 2nd Level Cache: 10.883 ms
mit 2nd Level Cache für Land: 6.549 ms
Optimierung von JPA-Anwendungen 43
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
Optimierung von JPA-Anwendungen 44
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
Optimierung von JPA-Anwendungen 45
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
Optimierung von JPA-Anwendungen 46
Inheritance
SINGLE_TABLE
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Vehicle
{
…
Optimierung von JPA-Anwendungen 47
Inheritance
JOINED
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Vehicle
{
…
Optimierung von JPA-Anwendungen 48
Inheritance
TABLE_PER_CLASS
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle
{
…
Optimierung von JPA-Anwendungen 49
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
Optimierung von JPA-Anwendungen 50
Inheritance
Optimale Performanz liefern
SINGLE_TABLE und TABLE_PER_CLASS
Aber: Auch andere Implikationen
Genaue Analyse notwendig
Optimierung von JPA-Anwendungen 51
Providerabhängiges
Lazy-Varianten
Cache-Strategien
Prepared Statement Cache
Change Detection
DB Dialects
…
Optimierung von JPA-Anwendungen 52
Fazit
Viele Optimierungen providerunabhängig möglich
Wesentlich:
Lazy Loading
Caching
Genaue Analyse notwendig
Messen
Kein Selbstzweck
Optimierung von JPA-Anwendungen 53
More
Seminare zum Thema, z. B.
Java Persistence API (JPA)
Power Workshop Java EE 6/7
http://ips-it-schulungen.de/Kurse/Java
http://javaeeblog.wordpress.com/
http://expertenkreisjava.blogspot.de/
 dirk.weil@gedoplan.de
@dirkweil
dirk.weil@gedoplan.deOptimierung von JPA-Anwendungen 54

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (6)

Oracle Database Appliance, Partnerwebcast, November 2011
Oracle Database Appliance, Partnerwebcast, November 2011Oracle Database Appliance, Partnerwebcast, November 2011
Oracle Database Appliance, Partnerwebcast, November 2011
 
Die Oracle Datenbank als Service in der Oracle Cloud, November 2012
Die Oracle Datenbank als Service in der Oracle Cloud, November 2012Die Oracle Datenbank als Service in der Oracle Cloud, November 2012
Die Oracle Datenbank als Service in der Oracle Cloud, November 2012
 
Oracle GoldenGate: Synchronisation zwischen Oracle und MySQL Datenbanken, Nov...
Oracle GoldenGate: Synchronisation zwischen Oracle und MySQL Datenbanken, Nov...Oracle GoldenGate: Synchronisation zwischen Oracle und MySQL Datenbanken, Nov...
Oracle GoldenGate: Synchronisation zwischen Oracle und MySQL Datenbanken, Nov...
 
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)
 
Oracle Database In-Memory Advisor (Deutsch)
Oracle Database In-Memory Advisor (Deutsch)Oracle Database In-Memory Advisor (Deutsch)
Oracle Database In-Memory Advisor (Deutsch)
 
Feige sein
Feige seinFeige sein
Feige sein
 

Andere mochten auch

Web 2.0 [autoguardado]
Web 2.0 [autoguardado]Web 2.0 [autoguardado]
Web 2.0 [autoguardado]
proferodrigo56
 
Ms 6 marketing for managers
Ms 6 marketing for managersMs 6 marketing for managers
Ms 6 marketing for managers
smumbahelp
 
Animais muito mais que humanos
Animais muito mais que humanos Animais muito mais que humanos
Animais muito mais que humanos
guest18cd549
 

Andere mochten auch (18)

Performance Tuning with JPA 2.1 and Hibernate (Geecon Prague 2015)
Performance Tuning with JPA 2.1 and Hibernate (Geecon Prague 2015)Performance Tuning with JPA 2.1 and Hibernate (Geecon Prague 2015)
Performance Tuning with JPA 2.1 and Hibernate (Geecon Prague 2015)
 
Hibernate performance tuning
Hibernate performance tuningHibernate performance tuning
Hibernate performance tuning
 
JPA Best Practices
JPA Best PracticesJPA Best Practices
JPA Best Practices
 
Optimierung von JPA-­Anwendungen
Optimierung von JPA-­AnwendungenOptimierung von JPA-­Anwendungen
Optimierung von JPA-­Anwendungen
 
Cesgranrio 2014-petrobras-engenheiro-a-civil-junior-gabarito
Cesgranrio 2014-petrobras-engenheiro-a-civil-junior-gabaritoCesgranrio 2014-petrobras-engenheiro-a-civil-junior-gabarito
Cesgranrio 2014-petrobras-engenheiro-a-civil-junior-gabarito
 
Web 2.0 [autoguardado]
Web 2.0 [autoguardado]Web 2.0 [autoguardado]
Web 2.0 [autoguardado]
 
Memorial
MemorialMemorial
Memorial
 
A Chuva
A ChuvaA Chuva
A Chuva
 
Advertising management (part 2)
Advertising management (part   2)Advertising management (part   2)
Advertising management (part 2)
 
Ms 6 marketing for managers
Ms 6 marketing for managersMs 6 marketing for managers
Ms 6 marketing for managers
 
Discar
DiscarDiscar
Discar
 
Pela Internet
Pela InternetPela Internet
Pela Internet
 
Animais muito mais que humanos
Animais muito mais que humanos Animais muito mais que humanos
Animais muito mais que humanos
 
Blog
BlogBlog
Blog
 
Rosa
RosaRosa
Rosa
 
Ms 09 managerial economics
Ms   09 managerial economicsMs   09 managerial economics
Ms 09 managerial economics
 
Expresso101
Expresso101Expresso101
Expresso101
 
Guia De Redação
Guia De RedaçãoGuia De Redação
Guia De Redação
 

Ähnlich wie Optimierung von JPA-Anwendungen

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
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Way
jubecker
 
Lightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPALightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPA
mh0708
 
Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)
Michael Romer
 
Best Practices SharePoint and SQL Installation
Best Practices SharePoint and SQL InstallationBest Practices SharePoint and SQL Installation
Best Practices SharePoint and SQL Installation
Samuel Zürcher
 

Ähnlich wie Optimierung von JPA-Anwendungen (20)

javaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevelsjavaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
 
Datenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence ApiDatenbankzugriff mit der Java Persistence Api
Datenbankzugriff mit der Java Persistence Api
 
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
 
Oracle ETL Herausforderungen - OPITZ CONSULTING - Till Sander - Wolfgang Rütter
Oracle ETL Herausforderungen - OPITZ CONSULTING - Till Sander - Wolfgang RütterOracle ETL Herausforderungen - OPITZ CONSULTING - Till Sander - Wolfgang Rütter
Oracle ETL Herausforderungen - OPITZ CONSULTING - Till Sander - Wolfgang Rütter
 
Wordpress on steroids
Wordpress on steroidsWordpress on steroids
Wordpress on steroids
 
JPA – Der Persistenz-­Standard in der Java EE und SE
JPA – Der Persistenz-­Standard in der Java EE und SEJPA – Der Persistenz-­Standard in der Java EE und SE
JPA – Der Persistenz-­Standard in der Java EE und SE
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Way
 
Kritische app performance erfolgreich optimieren mit Bison
Kritische app performance erfolgreich optimieren mit BisonKritische app performance erfolgreich optimieren mit Bison
Kritische app performance erfolgreich optimieren mit Bison
 
DB-Schema-Evolution mit LiquiBase
DB-Schema-Evolution mit LiquiBaseDB-Schema-Evolution mit LiquiBase
DB-Schema-Evolution mit LiquiBase
 
Java EE 5
Java EE 5Java EE 5
Java EE 5
 
Query Result Caching
Query Result CachingQuery Result Caching
Query Result Caching
 
Erfahrungsbericht über die Aktualisierung einer Consumer Mailplattform mit UC...
Erfahrungsbericht über die Aktualisierung einer Consumer Mailplattform mit UC...Erfahrungsbericht über die Aktualisierung einer Consumer Mailplattform mit UC...
Erfahrungsbericht über die Aktualisierung einer Consumer Mailplattform mit UC...
 
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
 
Lightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPALightweight AOP with CDI and JPA
Lightweight AOP with CDI and JPA
 
SharePoint Testing mit Visual Studio 2012
SharePoint Testing mit Visual Studio 2012SharePoint Testing mit Visual Studio 2012
SharePoint Testing mit Visual Studio 2012
 
Überblick: 18c und Autonomous Data Warehouse Cloud (ADWC)
Überblick: 18c und Autonomous Data Warehouse Cloud (ADWC)Überblick: 18c und Autonomous Data Warehouse Cloud (ADWC)
Überblick: 18c und Autonomous Data Warehouse Cloud (ADWC)
 
Effiziente datenpersistierung mit JPA 2.1 und Hibernate
Effiziente datenpersistierung mit JPA 2.1 und HibernateEffiziente datenpersistierung mit JPA 2.1 und Hibernate
Effiziente datenpersistierung mit JPA 2.1 und Hibernate
 
Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)Doctrine 2 - An Introduction (German)
Doctrine 2 - An Introduction (German)
 
Infinispan - NoSQL für den Enterprise Java Alltag
Infinispan - NoSQL für den Enterprise Java AlltagInfinispan - NoSQL für den Enterprise Java Alltag
Infinispan - NoSQL für den Enterprise Java Alltag
 
Best Practices SharePoint and SQL Installation
Best Practices SharePoint and SQL InstallationBest Practices SharePoint and SQL Installation
Best Practices SharePoint and SQL Installation
 

Optimierung von JPA-Anwendungen

  • 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Vorträge Seminare Veröffentlichungen Optimierung von JPA-Anwendungen 2
  • 4. 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; … Optimierung von JPA-Anwendungen 4
  • 5. 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; Optimierung von JPA-Anwendungen 5
  • 6. Id-Generierung Alternative: BYO-ID (selbst machen, i. a. im Konstruktor) Id auch in transitiven Objekten gesetzt Insert ohne Zusatzaufwand Achtung: i. A. nicht trivial Z. B.: UUID @Id private String id = new com.eaio.uuid.UUID().toString(); Optimierung von JPA-Anwendungen 6
  • 7. Id-Generierung @GeneratedValue signifikant langsamer (OOTB) Derby EclipseLink MySQL EclipseLink Oracle EclipseLink Derby Hibernate MySQL Hibernate Oracle Hibernate BYO-ID 19.864 11.659 22.478 19.240 9.684 7.126 AUTO 21.034 13.537 23.663 74.804 12.214 70.814 0 10.000 20.000 30.000 40.000 50.000 60.000 70.000 80.000 Millisekunden Insert 50.000 einfache Entries in 1.000er Batches Optimierung von JPA-Anwendungen 7
  • 8. 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; Optimierung von JPA-Anwendungen 8
  • 9. Id-Generierung 0 10.000 20.000 30.000 40.000 50.000 60.000 70.000 80.000 1 10 100 1000 Laufzeit vs. Allocation Size Optimierung von JPA-Anwendungen 9
  • 10. Relationship Loading Relationen werden durch Felder mit @OneToOne, …, @ManyToMany repräsentiert @Entity public class Book { @ManyToOne public Publisher publisher; @Entity public class Publisher { @OneToMany(mappedBy="publisher") public List<Book> books; Optimierung von JPA-Anwendungen 10
  • 11. Relationship Loading Relationen-Parameter: fetch Referenzierte Entities direkt laden? EAGER: Direkt LAZY: Später bei Bedarf @ManyToOne(fetch = FetchType.LAZY) private Artikel artikel; Optimierung von JPA-Anwendungen 11
  • 12. Relationship Loading Bsp.: Auftragsposition bearbeiten Ist Owner der n:1-Relation zu Artikel Kunde Auftrag Auftrags Position ArtikelLand 1 * 1 * * 1 1* @Entity public class AuftragsPosition { @ManyToOne private Artikel artikel; Optimierung von JPA-Anwendungen 12
  • 13. Relationship Loading Annahme: Verwendet nur AuftragsPosition AuftragsPosition aufPos = em.find(AuftragsPosition.class, id); … select … from AuftragsPosition where … select … from AuftragsPosition left outer join Artikel where … @ManyToOne private Artikel artikel; @ManyToOne(fetch=FetchType.LAZY) private Artikel artikel; Optimierung von JPA-Anwendungen 13
  • 14. Relationship Loading Annahme: Verwendet auch Artikel AuftragsPosition aufPos = em.find(AuftragsPosition.class, id); Artikel artikel = aufPos.getArtikel(); … select … from AuftragsPosition where … select … from Artikel where … select … from AuftragsPosition left outer join Artikel where … @ManyToOne private Artikel artikel; @ManyToOne(fetch=FetchType.LAZY) private Artikel artikel; Optimierung von JPA-Anwendungen 14
  • 15. Relationship Loading Bsp.: Kunde bearbeiten Ist Owner der 1:n-Relation zu Auftrag Kunde Auftrag Auftrags Position ArtikelLand 1 * 1 * * 1 1* @Entity public class Kunde { @OneToMany(mappedBy="kunde") private Set<Auftrag> auftraege; Optimierung von JPA-Anwendungen 15
  • 16. Relationship Loading Annahme: Verwendet nur Kunde Kunde kunde = em.find(Kunde.class, id);… select … from Kunde where … select … from Kunde left outer join Auftrag left outer join AuftragsPosition where … @ManyToOne(fetch=FetchType.EAGER) private Set<Auftrag> auftraege; @ManyToOne private Set<Auftrag> auftraege; Optimierung von JPA-Anwendungen 16
  • 17. Relationship Loading Messergebnis (1000 Interationen, Hibernate, MySQL) EAGER LAZY Nur AuftragsPosition 2.967 ms 2.505 ms - 15 % Auch Artikel 2.959 ms 4.305 ms + 45 % Nur Kunde 30.295 ms 4.848 ms - 84 % = Default-Einstellung Optimierung von JPA-Anwendungen 17
  • 18. Relationship Loading Fazit: Zugriffsverhalten genau analysieren Default ist schon recht gut Besser: Immer LAZY verwenden und bei Bedarf nachladen providerspezifische Mittel left join fetch Load/Fetch Graph (ab JPA 2.1) Optimierung von JPA-Anwendungen 18
  • 19. Relationship Loading Fetch Joins mit JPQL leider nur einstufig erlaubt select ap from Auftragsposition ap left join fetch ap.artikel ... Optimierung von JPA-Anwendungen 19
  • 20. 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) .fetch(AuftragsPosition_.artikel); … Optimierung von JPA-Anwendungen 20
  • 21. Fetch Tuning ToMany-Fetching: "N+1"-Problem z.B. Lesen der User inkl. Groups + Permissions SELECT ... FROM USER SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND … SELECT ... FROM PERMISSION WHERE GROUP_ID=? SELECT ... FROM PERMISSION WHERE GROUP_ID=? SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND … SELECT ... FROM USER_GROUP t0, GROUP t1 WHERE t0.USER_ID=? AND … Optimierung von JPA-Anwendungen 21
  • 22. 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(); Optimierung von JPA-Anwendungen 22
  • 23. Fetch Tuning Lösungsansatz 2: Batch Fetching erzeugt 1 SELECT pro 'Ebene' @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 OpenJPA @EagerFetchMode (nur für EAGER!) JOIN (='PARALLEL') Optimierung von JPA-Anwendungen 23
  • 24. Basic Attribute Loading Fetch-Strategie auch für einfache Werte wählbar Lazy Loading sinnvoll bei selten genutzten Werten umfangreichen Daten @Basic(fetch = FetchType.LAZY) private String longAdditionalInfo; Optimierung von JPA-Anwendungen 24
  • 25. Basic Attribute Loading Messergebnis Lesen von Kunden 10 'ungenutzte' Strings à 150 chars 1000 Interationen, EclipseLink, Oracle EAGER LAZY 7.204 ms 6.820 ms -5 % = Default-Einstellung Optimierung von JPA-Anwendungen 25
  • 27. Lazy-Load-Verfahren Instrumentierung @Basic(fetch = FetchType.LAZY) private String longAdditionalInfo; get(…) ? DB Optimierung von JPA-Anwendungen 27
  • 28. Bytecode-Instrumentierung  = Standard  = Providerspezifische Konfiguration erforderlich Eclipselink Verfahren SE EE @Basic Entity Instrumentation   @xxxToOne Entity Instrumentation   @xxxToMany Collection Proxy   Hibernate Verfahren SE EE @Basic Entity Instrumentation   @xxxToOne Attribute Proxy   @xxxToMany Collection Proxy   Optimierung von JPA-Anwendungen 28
  • 30. First Level Cache Standard Je EntityManager Enthält in Sitzung geladene Objekte Achtung: Speicherbedarf! ggf. explizit entlasten (clear, detach) EntityManager 1st Level Cache Optimierung von JPA-Anwendungen 30
  • 31. 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! Optimierung von JPA-Anwendungen 31
  • 32. 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(); Optimierung von JPA-Anwendungen 32
  • 33. 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] Optimierung von JPA-Anwendungen 33
  • 34. 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(); … } Optimierung von JPA-Anwendungen 34
  • 35. Query Cache EclipseLink Hibernate: (Aktivierung in der Konfiguration notwendig) TypedQuery<Kunde> query = em.createQuery(…); query.setHint("org.hibernate.cacheable", true); … TypedQuery<Kunde> query = em.createQuery(…); query.setHint("eclipselink.cache-usage", "CheckCacheThenDatabase"); … Optimierung von JPA-Anwendungen 35
  • 36. Second Level Cache JPA 2.0 unterstützt 2nd Level Cache nur rudimentäre Konfiguration Providerspezifische Konfiguration in der Praxis unabdingbar JPA Provider EntityManager 2nd Level Cache 1st Level Cache Optimierung von JPA-Anwendungen 36
  • 37. Second Level Cache Providerspezifische Implementierung Cache-Provider Infinispan, EHCache, OSCache, … Cache-Strategien read-only, read-write, … Storage Memory, Disk, Cluster, … Optimierung von JPA-Anwendungen 37
  • 38. Second Level Cache Wirkt applikationsweit Semantik ähnlich HashMap Ladereihenfolge: 1st Level Cache (EntityManager) 2nd Level Cache, falls enabled DB Optimierung von JPA-Anwendungen 38
  • 39. Second Level Cache Vorteil bei häufig genutzten Daten Konstanten selten veränderte Daten nur von dieser Anwendung veränderte Daten Optimierung von JPA-Anwendungen 39
  • 40. 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 * Optimierung von JPA-Anwendungen 40
  • 41. Second Level Cache Konfiguration lt. Spec <persistence-unit name="…"> <provider>…</provider> <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode> … Cache aktiv für … ALL alle Entities NONE keine Klasse ENABLE_SELECTIVE nur @Cacheable(true) DISABLE_SELECTIVE alle außer @Cacheable(false) @Entity @Cacheable(true) public class Land { … Optimierung von JPA-Anwendungen 41
  • 42. Second Level Cache EclipseLink Default: DISABLE_SELECTIVE Hibernate bis Version 3.x ignoriert Standard-Konfig benötigt eigene Annotation @Entity @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) public class Land { … Optimierung von JPA-Anwendungen 42
  • 43. Second Level Cache Messergebnis (1000 Interationen, EclipseLink, Oracle) ohne 2nd Level Cache: 10.883 ms mit 2nd Level Cache für Land: 6.549 ms Optimierung von JPA-Anwendungen 43
  • 44. 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 Optimierung von JPA-Anwendungen 44
  • 45. 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 Optimierung von JPA-Anwendungen 45
  • 46. 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 Optimierung von JPA-Anwendungen 46
  • 50. 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 Optimierung von JPA-Anwendungen 50
  • 51. Inheritance Optimale Performanz liefern SINGLE_TABLE und TABLE_PER_CLASS Aber: Auch andere Implikationen Genaue Analyse notwendig Optimierung von JPA-Anwendungen 51
  • 52. Providerabhängiges Lazy-Varianten Cache-Strategien Prepared Statement Cache Change Detection DB Dialects … Optimierung von JPA-Anwendungen 52
  • 53. Fazit Viele Optimierungen providerunabhängig möglich Wesentlich: Lazy Loading Caching Genaue Analyse notwendig Messen Kein Selbstzweck Optimierung von JPA-Anwendungen 53
  • 54. More Seminare zum Thema, z. B. Java Persistence API (JPA) Power Workshop Java EE 6/7 http://ips-it-schulungen.de/Kurse/Java http://javaeeblog.wordpress.com/ http://expertenkreisjava.blogspot.de/  dirk.weil@gedoplan.de @dirkweil dirk.weil@gedoplan.deOptimierung von JPA-Anwendungen 54