Mittwoch, 7. März 2012

Behandlung von IDs / Performance und Optimierung 

Wird ein Object/Relation Mapper wie bspw. Hibernate verwendet, so muss jede gemanagte Entity, die bspw. in einer Tabelle persistiert wird, eine ID besitzen.
Es muss also etwas geben, dass eine solche Entity eindeutig identifiziert.
In JPA dient die Annotation @Id dazu.

Die Attribute zur Identifizierung können nach folgenden Aspekten ausgewählt werden:

  1. Nutzung eines fachlichen Schlüssels
  2. Nutzung/Generierung eines technischen Schlüssels
Variante 1 lässt sich nicht immer für eine Entity finden.
Für Variante 2 müssen für neue Objekte neue IDs generiert werden.

JPA Generatoren

Unter JPA kommen hier Generatoren zum Einsatz:
@GeneratedValue

Es gibt 3 Generatoren, die über den Annotation-Parameter strategy ausgewählt wird:
  1. IDENTITY
  2. SEQUENCE
  3. TABLE
  4. AUTO

IDENTITY

Bei IDENTITY kommt eine Autoincrement-Spalte zum Einsatz, wenn die darunterliegende DB dies unterstützt.

SEQUENCE

Bei SEQUENCE wird ein eigener DB-seitiger Generator verwendet, der sich um das Hochzählen des Wertes kümmert.

TABLE

Bei TABLE wird eine Tabelle hibernate_sequences angelegt, die die Werte des Generators hält.

AUTO

Bei AUTO entscheidet hibernate anhand des eingestellten db-Dialekts, welcher Generator am Besten zu verwenden ist.

JPA PERFORMANCE

Performance
Grundsätzlich bedeuten technische Schlüssel eine schlechtere Performance, da beim persist der EntityManager/HibernateSessionFactory die von der DB vergebene ID auslesen muss.
Wehe den Datenbanken, die diese wichtige Operation per API nicht speziell anbieten.
Gibt es vom Treiber keine spezielle Operation bzw. Möglichkeit dies effizient einzulesen,
dann sind schlechtere Insert-Operation vorprogrammiert wie auf anderen Datenbanken.
Die AUTO-strategy kann auf bestimmten Datenbanken Performance kaputtmachen.
So kommt bei der Oracle-Datenbank eine Sequenz zum Einsatz, aber mit leider einer vorkonfigurierten allocationSize von 1.
Dies kann bei AUTO-strategy nicht eingestellt werden und bedeutet somit, 
dass die Insert-Performance sehr schlecht ist, da nach jedem Insert über den Treiber die nächste verfügbare ID von der Sequenz ausgelesen werden muss.
So wird im Standard bei manueller Anlage oder bei Nutzung von Datenbanktools auf der DB2 und Oracle Sequences angelegt, die die nächsten 20 IDs cachen, so dass nicht nach jeder Einfügeoperation das Sequenzobjekt hierzu befragt werden muss.
 CREATE SEQUENCE XY
      START WITH 1
      INCREMENT BY 1
      NO MAXVALUE
      NO CYCLE
      CACHE 20;
     INSERT INTO ORDERS (ORDERNO, CUSTNO)
       VALUES (NEXT VALUE FOR XY, 123456);


Performance @GeneratedValue

Ist besondere Performance gefragt, kann man die Annotation @GeneratedVaule rausnehmen, so dass der JPA-Provider nicht mehr in der Verantwortung ist, eine ID zu ermitteln und bei persist zu setzen.
Dann muss man selber für eine ID-Generierung sorgen, dies kann hinsichtlich schwacher Treiber, deutlich schneller sein.

UUID-Klasse

Im java.util-Package gibt es seit Java 1.5 eine UUID-Klasse mit der man UUIDs generieren kann.
Eventuell sichert man dies noch mit eindeutigen Informationen aus dem jeweiligen Kontext ab, so dass die UUID wirklich eindeutig ist und nie per Zufall doppelt vergeben werden kann.
Dies hätte den Vorteil, dass nach der persist()-Methode ein Nachschlagen des vergeben Wertes für den DB-Treiber wegfiele.

Eine gute weiterführende Lektüre zum Thema ID Behandlung bietet folgendes Buch
(Kapitel 4 Abschnitt Mapping the Primary Key):



Keine Kommentare:

Kommentar veröffentlichen