2012-04-25 36 views
14

Sto scrivendo un'applicazione Web utilizzando Hibernate 3.Hibernate Performance Best Practice?

Quindi, dopo un po 'ho notato che qualcosa era lento. Così ho testato il profiler per l'ibernazione e ho scoperto che l'ibernazione causerà irragionevolmente molte chiamate db per operazioni semplici. Il motivo è naturalmente che carico un oggetto (questo oggetto ha diversi "genitori") e questi "genitori" hanno altri "genitori". Quindi, in sostanza, l'ibernazione li carica tutti, anche se ho solo bisogno dell'oggetto base. Ok, quindi ho guardato in pigro-caricamento. Il che mi porta all'eccezione Lazyloading, perché ho una webapp MVC.

Quindi ora sono un po 'confuso su quale sia il mio approccio migliore a questo. In generale tutto ciò di cui ho bisogno è aggiornare un singolo campo su un oggetto. Ho già la chiave dell'oggetto.

Devo: 1. Scavare nel modo di caricamento lento. E poi riscrivi la mia app per una vista a sessione aperta? 2. Scava nel caricamento lento. E poi riscrivi il mio dao per essere più specifico. Per esempio. scrivendo metodi DAO che restituiranno oggetti instanciati con solo ciò che è necessario per ogni caso d'uso? Potrebbero esserci molti altri metodi ... 3. Scratch ibernare e farlo da solo? 4. Non posso davvero pensare ad altre soluzioni in questo momento. Eventuali suggerimenti?

Qual è la migliore pratica?

risposta

25
  • Non utilizzare join a meno che non sia realmente necessario. Non ti permetteranno di utilizzare né il caricamento lazy né l'uso della cache di secondo livello per le associazioni
  • Usa lazy = "extra" per le raccolte di grandi dimensioni, non recupererà tutti gli elementi finché non lo chiedi, puoi anche usare le dimensioni() metodo, ad esempio, senza ottenere elementi dal DB
  • Utilizzare il metodo load() se è possibile poiché non emette una query di selezione finché non è richiesta. Per esempio. se avete un libro e un autore e che si desidera associare insieme, tale volontà non emetterà alcun seleziona, unico singolo inserto:

    Book b = (Book) session.load(Book.class, bookId); 
    Author a = (Author) session.load(Author.class, authorId); 
    b.setAuthor(a); 
    session.save(b); 
    
  • Utilizzare chiamato query (nei file HBM o in @NamedQuery) in modo che non vengano analizzati durante ogni query.Non utilizzare Criteri API fino a quando è necessario (rende impossibile utilizzare la cache PreparedStatement in questo caso)

  • Uso OSIV nella vostra applicazione web dal momento che caricare i dati solo quando/se è necessario
  • Utilizzare sola lettura modalità solo per selezione: session.setReadOnly(object, true). In questo modo Hibernate non manterrà un'istantanea originale dell'entità selezionata nel contesto permanente per ulteriori verifiche sporche.
  • Cache di secondo livello utente e cache di query per i dati di sola lettura e di sola lettura.
  • Utilizzare FlushMode.COMMIT anziché AUTO in modo che Hibernate non esegua la selezione prima degli aggiornamenti, ma si tenga pronto che ciò potrebbe comportare la scrittura di dati non aggiornati (sebbene il blocco ottimistico possa essere d'aiuto).
  • Dai un'occhiata al recupero in batch (batch-size) per selezionare più entità/collezioni contemporaneamente anziché emettere query separate per ognuna.
  • Le query come "seleziona nuova Entità (id, someField) dall'entità" per recuperare solo i campi obbligatori. Dai un'occhiata ai trasformatori dei risultati.
  • Utilizzare le operazioni batch (come eliminare) se necessario
  • Se si utilizzano query native, specificare esplicitamente quali aree della cache devono essere invalidate (per impostazione predefinita, tutte).
  • Dai un'occhiata al percorso materializzato e ai set nidificati per strutture ad albero.
  • Impostare c3p0.max_statements per abilitare la cache PreparedStatment nel pool e abilitare la cache dell'istruzione del DB se è disattivata per impostazione predefinita.
  • Usa StatelessSession se è possibile, supera i controlli sporchi, a sfioro, intercettori, ecc
  • Non utilizzare l'impaginazione (setMaxResults(), setFirstResult()) insieme con le query che contengono unisce alle collezioni, questo si tradurrà in tutti i record estratti da database e paginazione avverranno in memoria da Hibernate. Se vuoi l'impaginazione, idealmente non dovresti usare i join. Se non puoi sfuggire, usa di nuovo il recupero in batch.

In realtà ci sono molti trucchi, ma al momento non riesco a ricordare altro.

+0

OSIV puoi spiegare che non ho ricevuto –

1

Credo che vogliate rivedere questo section in the Hibernate manual.

Mi aspetto che il tuo problema originale di "... irragionevolmente molte chiamate in db ..." sia un'istanza di quello che chiamano "N + 1 seleziona il problema". Se è così, hanno opzioni su come affrontarlo.

  1. Imposta il tipo di recupero. Quindi avrai una singola selezione con diversi join, supponendo che non ci siano raccolte intermedie.
  2. Il caricamento è lento.
  3. Probabilmente alcuni altri, ad esempio FetchProfiles con cui non ho esperienza.

I primi due possono essere specificati a livello di associazione, e tipo di recupero può essere sostituito a livello di query. Dovresti essere in grado di ottenere che la tua query faccia solo ciò di cui hai bisogno, non di più, e fallo con una query SQL "buona" con questi strumenti.

3

Come ho spiegato in this article o il mio High-Performance JavaPersistence book, ci sono molte cose che potete fare per accelerare le prestazioni di Hibernate, come:

  1. Enabling SQL statement logging in modo che è possibile convalidare tutte le istruzioni e persino detect N+1 query problems during testing.
  2. gestione delle connessioni database e monitoraggio utilizzando FlexyPool
  3. JDBC batching per ridurre il numero di andata e ritorno necessario alla presentazione INSERT, UPDATE e DELETE.
  4. JDBC Statement caching
  5. ottimizzatori identificatore JPA come pooled or pooled-lo
  6. Scelta di tipi di colonne compatte
  7. Usare i giusti rapporti: bidirectional @OneToMany instead of unidirectional one, utilizzando @MapsId for @OneToOne, using Set for @ManyToMany
  8. Uso inheritance the right way e preferring SINGLE_TABLE for performance reasons
  9. Minding the Persistence Context size and avoiding long-running transactions
  10. Utilizzando OS caching , Memorizzazione nella cache del DB prima di passare alla cache di secondo livello h è utile anche per off-caricare il nodo primario quando si fa la replica del database
  11. Scatena funzionalità di query di database tramite SQL native queries
  12. Split scrive tra più one-to-one entità per reduce optimistic locking false positives e ottenere una migliore possibilità di colpire la cache del database anche quando si modificano determinate entità.