2015-09-15 12 views
7

Ho sofferto per diversi giorni con una query su ibernazione contro un database Oracle. Qualcosa di simile è usato per alimentare i record in una griglia.Hibernate con query sql con parametri lenta e sessioni oracle attive

SELECT 
    fields 
FROM 
    tables and JoinedTables 
WHERE 
     Field1 >= :value1 
    AND Field2 = :value2 
    AND Field3 = :value3 
Order By MaintTable.Id Desc 

Utilizzo di questo approccio in un metodo Spring Java + Hibernate 4.2.

Ogni campo filtrato viene indicizzato correttamente e creato un indice di funzione su Maintable.Id Discendente per migliorare le prestazioni.

In un primo momento ho pensato che fosse pool di sessione/connessione non viene gestito correttamente, così ho cambiato per StatelessSession e aggiungi a Session.close():

query.setCacheable(false) 
       .setTimeout(30) 
       .setReadOnly(true); 
... 
... 
//Pagination 
query.setMaxResults(rows); 
query.setFirstResult(HelperMethod(page, rows)); 

result = (List<CertificateViewEnt>) query.list(); 
session.close(); 
return result; 

Non ha risolto. Query esegue un paio di volte ok, ma per qualche motivo sconosciuto e utilizzando valori che erano già stati eseguiti in precedenza con successo, si blocca, lascia la sessione aperta in Oracle (stato = ATTIVO) e fallisce il timeout. La stessa query eseguita su Oracle su qualsiasi client SQL e decine di volte con tutte le possibili combinazioni di parametri viene eseguita con prestazioni estreme, circa 400ms, per 10 record alla volta.

Dopo aver letto alcuni articoli qua e là, Link1 [Slow performance on Hibernate + Java but fast when I use TOAD with the same native Oracle query Link2: [query hangs oracle 10g

I supected di QueryPlan mal utilizzato da Hibernate e ha deciso di rimuovere tutti i filtri che utilizzano i parametri legati e inoltre, non ha risolto, anche se era un po 'meglio. Dopo un po 'impiccato quando si spostano in altre pagine come pagina 1, 2,3,4, ...

Dopo tutto questo, ho sospettato di SQL generato da metodi di Hibernate

query.setMaxResults(rows) 
query.setFirstResult(SomeHelperMethod(page, rows)); 

Perché sega a registro che venivano passati come parametri di collegamento a Oracle.

 ... 
     Order By Certificado.Id Desc) row_ 
     where rownum <= ?) 
    where rownum_ > ? 

ho visto anche questo nel Registro di traccia

2015-09-15 14:09:53 TRACE QueryPlanCache:200 - Located native-sql query plan in cache (SELECT /*+ INDEX(

e questo:

2015-09-15 14:09:53 TRACE BasicBinder:84 - binding parameter [2] as [VARCHAR] - E 
2015-09-15 14:09:53 DEBUG Loader:2031 - bindNamedParameters() 0 -> deleted [3] 
2015-09-15 14:09:53 TRACE BasicBinder:84 - binding parameter [3] as [INTEGER] - 0 
2015-09-15 14:09:53 TRACE Loader:1931 - Bound [7] parameters total 
/* 
SLOW here !!! Around 3 secs when query runs in ~0,300 secs via SQL client. 
And ACTIVE sessions are left running in Oracle. 
*/ 
2015-09-15 14:09:56 TRACE JdbcCoordinatorImpl:397 - Registering result set [[email protected]] 
2015-09-15 14:09:56 TRACE Loader:943 - Processing result set 

Alla fine ho dovuto abbandonare tutti i params legano Hibernate e attuate impaginazione calcolo personalizzato e scritto tutto SQL per recuperare le righe della pagina e sta funzionando e gestendo correttamente le sessioni db.

Quindi, la mia domanda è: Che cosa è letargo facendo behing le scene che impedisce la query da eseguire durante l'esecuzione sul database? C'è qualche problema noto con le query sui parametri di bind?

Non mi piace scrivere tutto il codice SQL e forzare l'analisi di questo SQL, quando ho dei parametri di bind.

Alcune note sull'ambiente: Tomcat e Oracle si trovano sullo stesso host.Quindi connessione di rete non è il problema

versione 4.2.15 Hibernate finale

La tabella ha circa 300k RECS nel database dev (1,5m sulla produzione) e mostra le pagine di 10, 20, 50 RECS alla volta , ordinati per chiave primaria Desc (sequenza generata)

Spero che alcuni esperti di Hibernate possano aiutarmi in questo modo, così posso ancora fidarmi delle query di Hibernate su progetti di database di grandi dimensioni. Grazie in anticipo.

+0

Avendo lo stesso problema. In MySQL Workbench la query impiega 0 ms. In Hibernate ci vogliono 1500ms. –

+0

Elimina tutti i parametri di Hibernate e crea la query SQL tutto da solo con tutti i parametri impostati nella stringa SQL. Ha funzionato per me. Proprio come se fosse una query della vecchia scuola JDBC. –

+0

Grazie per il suggerimento. Sicuramente vale la pena provare! –

risposta

1

Non so se questo è il tuo problema, ma Oracle sbircia i valori delle variabili di bind durante l'analisi di una query e quindi salva il piano di query per le esecuzioni future in modo che non debba continuare a analizzare la query ogni volta che è eseguire con una nuova serie di variabili di bind. Ma ogni tanto la query viene nuovamente analizzata. Se alcuni valori di variabili bind insoliti vengono passati durante un analisi, viene archiviato e utilizzato un piano errato. È una specie di maledizione delle variabili di bind. Riducono l'analisi, ma possono capovolgere il piano attorno a valori di variabili bind atipici quando le query vengono analizzate nuovamente. Suggerimenti possono aiutare. Utilizziamo i profili SQL per bloccare piani di query con variabili di binding che tendono a cambiare piano. A volte è possibile personalizzare quando e come vengono raccolte le statistiche di ottimizzazione in modo da creare un buon piano indipendentemente da quali valori vengono passati nelle variabili di binding.

In ogni caso, è qualcosa che vedo tutto il tempo e può o non può essere il tuo problema.

Bobby