2010-05-04 7 views
9

Abbiamo appena finito di profilare la nostra applicazione. (inizia a essere lenta). il problema sembra essere "in ibernazione".Usufruibile trabocchetto di prestazioni in letargo

È una mappatura legacy. Chi lavora e fa il lavoro. Anche lo shema relazionale è ok.

Ma alcune richieste sono lente come l'inferno.

Quindi, apprezzeremmo qualsiasi input sull'errore comune e normale fatto con l'ibernazione che finisce con una risposta lenta.

Esempio: Desideroso al posto di Lazy può cambiare dramaticly il tempo di risposta ....


Edit: Come al solito, leggere il manuale è spesso una buona idea. Un intero capitolo copertina questo argomento qui:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html

risposta

17

Una delle trappole più comuni è il famigerato n+1 selects problem. Per impostazione predefinita, Hibernate non carica i dati che non hai richiesto. Ciò riduce i consumi di memoria ma espone l'utente a n + 1 seleziona il problema che può essere evitato passando alla giusta strategia di recupero per recuperare tutti i dati necessari per caricare gli oggetti nello stato opportunamente inizializzato.

ma anche non prendere troppo o si incorrerà nel problema opposto, il cartesiano problema prodotto: invece di eseguire molte istruzioni SQL, si può finire per creare dichiarazioni che recuperano i troppi dati.

Questo è il punto principale dell'ottimizzazione: trovare il mezzo tra non abbastanza e troppi dati per ogni caso d'uso dell'applicazione (o almeno, per quello che richiede di essere sintonizzati).

Le mie raccomandazioni:

  • prima registrazione attivare SQL a livello di Hibernate
  • eseguire i casi d'uso critici (il 20% ha utilizzato l'80% dei casi) o addirittura tutti loro se si dispone di questo lusso
  • identificare le query sospette e ottimizzare il piano di recupero, verificare se gli indici sono utilizzati in modo appropriato, ecc
  • coinvolgere il vostro DBA
+0

Accettato per l'introduzione del problema di selezione N + 1. –

+0

L'alternativa n + 1 vs cartesiana (di solito attraverso "mostri unisce") è (ancora) un problema comune di ORM immaturo (anche dai principali editori di software). Fortunatamente, (N) Hibernate ha il batching delle query come un buon intermedio; raggrupperà le query e recupererà gli oggetti figlio tramite elenchi di ID o sottoselezioni, se caricando in modo lento o l'intero grafico dell'oggetto. Quindi, l'utente otterrà forse una dozzina di query anziché centinaia per n + 1 o un monster join con gigabyte di dati dei risultati. –

0

Una cosa che è successo alla mia azienda viene in mente. Si può vedere se il caricamento di un'entità carica anche qualche entità serialized, che verrà deserializzata ogni volta che l'entità viene caricata. Inoltre, quando si esegue il commit della transazione, è possibile effettuare un flush() (è configurabile). Se si svuota, per mantenere la persistenza, eseguirà un confronto sull'entità impegnata e su quella nel database. In questo caso farà un confronto sull'oggetto serialized, che richiede molto tempo.

Un'altra cosa che si potrebbe fare è controllare se si ha una inutile persistenza a cascata, ad esempio annotazione @Cascade({CascadeType.PERSIST, CascadeType.SAVE_UPDATE}) su colonne.

Un'altra cosa che potreste fare, che è non specificamente legato al letargo, è che si crea view s per fare una singola query, invece di fare un sacco di domande a tavoli diversi. Questo ha fatto una grande differenza per noi su una determinata caratteristica.

0

Come già accennato, la performance di Hibernate riguarda le impostazioni corrette. Una volta sono stato in grado di migliorare alcune velocità di aggiornamento della cache delle credenziali del fattore 10 (da 2 a 200 ms) passando a una sessione senza stato (quel particolare codice non dipendeva da alcun tipo di recupero pigro in modo da poter fare tranquillamente ciò che facevo) .

2

Mi piacerebbe approvare tutto ciò che Pascal ha detto, e solo menzionare inoltre che una soluzione al "recupero di troppi problemi di dati" è usare Hibernate Projections, e recuperare i dati in un DTO piatto, che consiste solo delle colonne davvero necessarie. Questa è specificamente un'opzione, quando non si ha intenzione di aggiornare i dati in questa sessione di ibernazione, quindi non avrà bisogno di oggetti mappati. Tratto da this article, che contiene ulteriori suggerimenti sulle prestazioni di Hibernate.

0

Mappatura di m: n e n: 1 relazioni sono root per frequenti problemi di prestazioni con Hibernate.

Hibernate Caching non può essere di grande aiuto se si utilizza HQL poiché Hibernate non può tradurre query in chiamate alla cache, quindi non può utilizzare la cache con HQL (almeno quando stavo leggendo il suo codice).

Se si desidera approccio semplice, veloce e leggero, posso consigliare fjorm

Dislaimer: Sono uno dei fondatori del progetto di fjorm

2

Gli errori più comuni sono le N + 1 decidono che si nascondono dietro le scene. In genere, questi non vengono rilevati prima della produzione e i soliti profiler non sono bravi a rivelarli.

È possibile provare un profiler interattivo come XRebel, che funziona ininterrottamente e rivela problemi durante lo sviluppo, quindi è possibile correggerli subito e addestrare i propri sviluppatori a non commettere quegli errori.

http://zeroturnaround.com/blog/hibernate-orm-with-xrebel-revealing-multi-query-issues-with-an-interactive-profiler/

XRebel showing SQL queries

0

come altri hanno già detto il N+1 problem è il problema comune nelle applicazioni JPA. Attualmente sto lavorando a uno strumento per il rilevamento precoce di questi problemi nei test delle unità e negli ambienti di test.Si chiama JDBC Sniffer, è open source e completamente gratuito

Esso consente di monitorare il numero di query eseguite sui vostri ambienti di test direttamente nel browser: enter image description here

Inoltre fornisce extensino ai quadri di unit test popolare per rilevare il problema N + 1 mentre si sviluppa il codice utilizzando annotazioni:

import com.github.bedrin.jdbc.sniffer.BaseTest; 
import com.github.bedrin.jdbc.sniffer.Threads; 
import com.github.bedrin.jdbc.sniffer.Expectation; 
import com.github.bedrin.jdbc.sniffer.Expectations; 
import com.github.bedrin.jdbc.sniffer.junit.QueryCounter; 
import org.junit.Rule; 
import org.junit.Test; 

public class QueryCounterTest extends BaseTest { 

    // Integrate JDBC Sniffer to your test using @Rule annotation and a QueryCounter field 
    @Rule 
    public final QueryCounter queryCounter = new QueryCounter(); 

    @Test 
    @Expectations({ 
      @Expectation(atMost = 1, threads = Threads.CURRENT), 
      @Expectation(atMost = 1, threads = Threads.OTHERS), 
    }) 
    public void testExpectations() { 
     executeStatement(); 
     executeStatementInOtherThread(); 
    } 

}