Hibernate subselect with Criteria API: slow performance in MySql
I have a subselect query (like the one below) in my hibernate mapping XML file. The purpose of this is to setup a basic SQL query which will then have various restrictions added via the Criteria API. I am displaying data which can be sorted, filtered, and searched with support for pagenation, and so the Criteria API is very useful for this.
<class name="className" table="tableName">
<subselect>
select x.col1 AS ID,
c.col2 AS a
....
from table1 x,
table2 y
where x.id = y.id
....
....
</subselect>
<id name="ID" column="ID"/>
<property name="a" column="a"/>
...
...
</class>
and the Java code will then add restrictions by doing something like
Criteria c = sessionFactory.getCurrentSession().createCriteria(tableName.class); c.add(Restrictions.allEq(m)); // where m is a hashmap containing column filters
However, it seems that the use of subselect to declare the basic query is causing very poor performance in MySQL. Hibernate puts the basic query into a subquery which is in the FROM clause of an outer query which has the added restrictions. So, just to be clear, Hibernate creates a query like A, whereas the query I want is B ie I don't want a subquery as it kills performance.
A: select _tmp.* B: select t1.col1,
from ( t1.col2
select t1.col1, from table1 t1,
t1.col2 table2 t2
from table1 t1, where t1.id = t2.id
table2 t2 and t1.col1 = 'blah'
where t1.id = t2.id order by t1.col desc
...
) _tmp
where _tmp.col1 = 'blah'
order by _tmp.col2 desc
So my question is how do I create the basic query in Hibernate without using subselect that allows me to use the Criteria API? What's the best way to get Hibernate the run query B rather than query A?
I understand that I can create named queries in the mapping file and load them, but that loads a query which, although allows me to add certain restrictions, it isn't as good as Criteria as it doesn't allow options for sorting etc ...
So are there any other options besides using either
<hibernate-mapping>
<class name="" table="">
<subselect></subselect>
</class>
</hibernate-mapping>
or
<hibernate-mapping>
<sql-query name="">
<return-scalar column="col" type="string"/>
</sql-query>
</hibernate-mapping>
as the first option degrades performance through the use of subquery, and the second option doesn't allow me (to the best of my knowledge anyway?) to use the Criteria API .
I have a solution, so I'm adding it here for reference.
My requirement was to use Hibernate to retrieve data from multiple tables and filter the resultset using the Criteria API. Being fairly new to Hibernate and Criteria, I went for the option I deemed easiest at the time which was to hand-craft some raw SQL to pull the data together and filter that data using Criteria. The use of subselect was the only way I knew at the time to load a hand-crafted SQL statement for futher amendment by Criteria functions. This worked fine in terms of functionality, but as detailed above, performed very poorly when running against MySQL.
What I didn't realise I could do with Criteria is use Aliases to place restrictions on associations. So I've ditched the raw SQL, and used Hibernate to retrieve my parent data object and used Criteria Aliases to add restrictions on all required associations. This method performs in under 100ms compared to 5 seconds.
链接地址: http://www.djcxy.com/p/37118.html