2015-09-15 7 views
7

Ich habe seit mehreren Tagen mit einer Abfrage auf Hibernate gegen eine Oracle-Datenbank gekämpft. So etwas wird zum Einspeisen von Datensätzen in ein Raster verwendet.Hibernate parametrisierte SQL-Abfrage langsam und aktiv Oracle-Sitzungen

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

Verwendung dieses Ansatzes in einer Spring Java + Hibernate 4.2-Methode.

Jedes gefilterte Feld ist korrekt indiziert und erstellt einen Funktionsindex auf Maintable.Id Descendent, um die Leistung zu verbessern.

Zuerst dachte ich, es war, Session/Connection-Pool nicht richtig verwaltet werden, damit ich geändert StatelessSession und fügen Sie diese 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; 

Es es nicht gelöst hat. Abfrage läuft ein paar Mal in Ordnung, aber aus einem unbekannten Grund, und die Verwendung von Werten, die bereits zuvor mit Erfolg ausgeführt wurden, hängt, Sitzung in Oracle (Status = ACTIVE) geöffnet und schlägt bei Timeout fehl. Die gleiche Abfrage, die auf jedem SQL-Client gegen Oracle ausgeführt wird und Dutzende von Malen mit allen möglichen Kombinationen von Parametern mit extremer Leistung, etwa 400 ms, für 10 Datensätze gleichzeitig ausgeführt wird.

Nach einigen Artikeln hier und da zu lesen, Link1 [Slow performance on Hibernate + Java but fast when I use TOAD with the same native Oracle query Link2: [query hangs oracle 10g

ich schlecht Auswertungsplan supected von Hibernate verwendet wurde, und beschlossen, alle Filter mit gebundenen Parametern zu entfernen und auch nicht gelöst haben, obwohl es ein bisschen besser war. Nach einer Weile hängen, wenn auf andere Seiten wie Page 1, 2,3,4 bewegen, ...

Nach alldem, vermutete ich, der durch Hibernate Methoden generiert SQL

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

Da Säge in Protokoll, dass sie wurden als Bindeparameter an Oracle übergeben.

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

Ich sah auch dies im Trace-Log

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

und diese:

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 

Schließlich hatte ich alle Hibernate binden params zu verlassen und implementiert individuelle Berechnung Paginierung und schrieb alle SQL um die Seitenzeilen abzurufen und um db-Sitzungen korrekt auszuführen und zu verwalten.

Also, meine Frage ist: Was die Szenen Behing Ist Ruhezustand zu tun, dass die Abfrage auszuführen verhindert, da es gegen die Datenbank ausgeführt wird? Gibt es ein bekanntes Problem mit Bind Parameter-Abfragen?

Ich mag es nicht wirklich, den ganzen SQL-Code zu schreiben und zwingt hart-Parsing dieses SQL, wenn ich Bindungsparameter habe.

Einige Anmerkungen zur Umgebung: Tomcat und Oracle sind auf demselben Host.So Netzwerkverbindung ist nicht das Problem

Hibernate Version 4.2.15 final

Der Tisch hat rund 300k recs in dev-Datenbank (1,5M auf Production) und zeigt Seiten von 10, 20, 50 recs zu einer Zeit, , sortiert nach Primärschlüssel Beschreibung (Sequence generated)

Ich hoffe, einige Hibernate-Experten können mir dabei helfen, sodass ich Hibernate-Abfragen bei großen Datenbankprojekten immer noch vertrauen kann. Vielen Dank im Voraus.

+0

Haben das gleiche Problem. In MySQL Workbench dauert die Abfrage 0 ms. In Hibernate dauert es 1500ms. –

+0

Nehmen Sie alle Hibernate-Parameter heraus und erstellen Sie die SQL-Abfrage selbst mit allen in der SQL-Zeichenfolge festgelegten Parametern. Es funktionierte für mich. Genau wie es eine JDBC Old School-Abfrage war. –

+0

Danke für den Tipp. Auf jeden Fall einen Versuch wert! –

Antwort

1

Ich weiß nicht, ob das Ihr Problem ist, aber Oracle späht Variablenwerte beim Analysieren einer Abfrage und speichert dann den Abfrageplan für zukünftige Ausführungen, damit die Abfrage nicht jedes Mal neu analysiert werden muss Führen Sie einen neuen Satz von Bind-Variablen aus. Aber ab und zu wird die Abfrage erneut analysiert. Wenn während einer Syntaxanalyse einige ungewöhnliche Werte für Bind-Variablen übergeben werden, wird ein ungültiger Plan gespeichert und verwendet. Es ist eine Art der Fluch der Bind-Variablen. Sie reduzieren das Parsen, können aber den Plan bei atypischen Bind-Variablenwerten umdrehen, wenn Abfragen erneut analysiert werden. Hinweise können helfen. Wir verwenden SQL-Profile, um Pläne von Abfragen mit Bindevariablen zu sperren, die dazu neigen, Pläne zu ändern. Manchmal können Sie anpassen, wann und wie Optimizer-Statistiken gesammelt werden, damit ein guter Plan erstellt wird, unabhängig davon, welche Werte an die Bindevariablen übergeben werden.

Wie auch immer, es ist etwas, was ich die ganze Zeit sehe und kann oder möglicherweise nicht dein Problem sein.

Bobby