Hibernate / Oracle Text related performance issue
Recently we experienced bad performance when searching for a keyword in a binary file using Hibernate 3.2 and Oracle Text from Oracle 10g.
Here is the case - we have a simple Oracle view which represents a candidate for a job and contains candidate’s CV as a binary file. Following is the Hibernate mapping for the view:
<hibernate-mapping>
<class name="Candidate" table="V_CANDIDATE" mutable="false">
<id name="id" type="long" column="CANDIDATE_ID"/>
<property name="language" type="string" column="LANG"/>
<property name="resume" type="blob" column="RESUME"/>
</class>
</hibernate-mapping>
Here is the Java code we used to search for keywords in the CV's:
Criteria query=getSession().createCriteria(Candidate.class);
query.add(Restrictions.eq("language",language));
query.add(Restrictions.sqlRestriction("contains({alias}.resume,?)>0",keyword,Hibernate.STRING))
query.list();
Here is the SQL statement Hibernate sent to Oracle as a result from the code above:
select * from V_CANDIDATE this_ where this_.LANG=? and contains(this_.resume,?)>0
Unfortunately it took more than 6 minutes to return any results or “no results” at all.
When I get the SQL statement from above that Hibernate generated, populated some values and issued it using Oracle SQL Developer it executes very fast!!!
select * from V_CANDIDATE this_ where this_.LANG='en' and contains(this_.resume,'{java}')>0
What could be the cause for this big difference in speed?
According to Hibernate documentation it is a best practice to use bind variables as we did. Quote:
"As in JDBC, always replace non-constant values by "?". Never use string manipulation to bind a non-constant value in a query! Even better, consider using named parameters in queries. "
Then I decided to try what will happen if I construct the SQL statement myself not relying on Hibernate and use Hibernate only to send the statement to Oracle. Here is the code:
StringBuffer sqlQuery=new StringBuffer("select * from V_CANDIDATE this_ where");
sqlQuery.append(" this_.LANG='"+language+"'");
sqlQuery.append(" and contains(this_.resume,");
sqlQuery.append("'"+keyword+"'");
sqlQuery.append(")>0");
SQLQuery query=getSession().createSQLQuery(sqlQuery.toString()).addEntity(Candidate.class);
query.list();
The result was staggering! Now the query run almost as fast as the one issued in Oracle SQL Developer.
Based on this a conclusion can be drawn that whenever we have to search for a keyword in a binary file using Hibernate and Oracle text the best practice is to use literals instead of bind variables