1

(I have read all the questions referenced in Hibernate Pagination using HQL but none of them is a possible solution in my case.)

I have a very complicated query written in HQL that has an order by on an indexed column. When Hibernate's built-in paging facilities (setFirstResult, etc.) are used, any page expect the first page takes several seconds to return where as the first page returns in <100ms.

Analysis of the explain plan by our DBA seems to suggest the DBMS decides to run the complicated query completely for all rows up to the upper bound of the page and then return the range specified.

For example, for the Hibernate generated query:

SELECT  * 
FROM     (SELECT   row_.*, ROWNUM rownum_
          FROM     (<very complicated queries>) row_
          WHERE    ROWNUM <= 100000) row2_
WHERE    rownum_ > 99990

The DBMS would run the row2_ sub-query to really fetch 100k rows and discard the first 99990 to give 10.

Obvious, the "very complicated query" is too complicated to be optimized by machine, so I decided to manually write a query that takes paging into account. The query is able to load any page within 100ms, but requires selecting from a sub-query (in the from clause). Unfortunately HQL does not support this, so I am stuck.

So does anyone know any alternative ways to do paging in HQL or ways to work around the no sub-query in from clause limitation?

Details:

Database is Oracle 11g. Hibernate version is 3.5.

The "very complicated query" selects about 10 different sub-queries in the select part from a single drive table with no joins in the main query. (This is to work around HQL's limitation on unrelated left joins.) Sorting can only happen on columns on the driving table.

The query I wrote basically selected all the IDs (of the driving table entity) that can appear in the "page" in a sub-query and then limited the main query to these IDs:

driverTable.id in 
 (SELECT   x.i
  FROM     (SELECT   z.i, ROWNUM r
            FROM     (SELECT     A.ID i
                      FROM       DrivingTable a
                      ORDER BY   A.ID DESC) z) x
  WHERE    x.r BETWEEN :page * 100 + 1 AND :page * 100 + 100)

This successfully tricked the query optimizer to apply the row number limits before computing the complicated main query.

Community
  • 1
  • 1
billc.cn
  • 7,187
  • 3
  • 39
  • 79

0 Answers0