Pagination with Oracle ROWNUM is sub-optimal

Description

Pagination with Oracle ROWNUM is sub-optimal

The feature works but result in sub-optimal SQL. The generated SQL is the following:

select * from ( select row_.*, rownum rownum_ from ( select this_.id as id3_0_, this_.version as version3_0_, this_.name as name3_0_, this_.type as type3_0_, this_.marketstatus as marketst5_3_0_ from Customer this_ order by this_.id asc ) row_ ) where rownum_ <= ? and rownum_ > ?

But this SQL is faster:

SELECT *
FROM (SELECT row_.*, ROWNUM rownum_
FROM (SELECT this_.ID AS id3_0_, this_.VERSION AS version3_0_,
this_.NAME AS name3_0_, this_.TYPE AS type3_0_,
this_.marketstatus AS marketst5_3_0_
FROM customer this_
ORDER BY this_.ID ASC) row_
WHERE ROWNUM <= ?)
WHERE rownum_ > ?

The second solution allows Oracle to use an optimization that can dramatically reduce the time of the query, especially one of the first page is retrieved.

See this link for an explanation of this optimization: http://decipherinfosys.wordpress.com/2007/08/09/paging-and-countstopkey-optimization/

Environment

None

Activity

Show:
Can Çermikli
October 18, 2010, 11:11 AM

I don't know why this problem is still open, but I think this problem is already resolved in Hibernate Dialect classes which are Oracle9iDialect, Oracle9Dialect and Oracle10gDialect. It generates SQL's like following:

select *
from ( select row_.*, rownum rownum_
from ( OUR_QUERY ) row_
where rownum <= MAX_ROWS )
where rownum_ > MIN_ROWS

But the way Hibernate's SQL generation for pagination in OracleDialect.java and Oracle8iDialect.java is the problematic one. Actually, it is not problematic, I think it is done intentionally in OracleDialect.java and Oracle8iDialect.java like this, because in Oracle 8i and below order by clause in the inner SQL stamement is not allowed. So, after 8i and Oracle's order by support, Hibernate's Dialect classes seem to change to support the new pagination.

So, if you use OracleDialect or Oracle8iDialect, Hibernate will generate sub-optimal native SQL's for pagination (of course if you use Oracle 8i and below, you need to use those ones), and
if you use Oracle9iDialect, Oracle9Dialect or Oracle10gDialect Hibernate will generate optimal native SQL's.

I hope it will be useful for the people who are searching for an answer for the problem.

Seth Wilcox
October 18, 2010, 7:39 PM

In oracle, to get maximum performance, you can explicitly tell the DB that you are doing a pagination query(by using the select /*+ FIRST_ROWS */ hint). When you do this, as soon as oracle has the number of rows you said you needed, the DB immediately stops and returns. Also, it can change the way the Cost based optimizer works. In my experience, it makes a noticeable and measurable impact on performance. The hint is what is still missing.

Nicolas Gavard
May 31, 2011, 10:57 AM

This article http://www.dba-oracle.com/t_sql_tuning_rownum_equals_one.htm talks about using rank() instead of rownum for better performance.

Brett Meyer
April 7, 2014, 5:46 PM

In an effort to clean up, in bulk, tickets that are most likely out of date, we're transitioning all ORM 3 tickets to an "Awaiting Test Case" state. Please see http://in.relation.to/Bloggers/HibernateORMJIRAPoliciesAndCleanUpTactics for more information.

If this is still a legitimate bug in ORM 4, please provide either a test case that reproduces it or enough detail (entities, mappings, snippets, etc.) to show that it still fails on 4. If nothing is received within 3 months or so, we'll be automatically closing them.

Thank you!

Brett Meyer
July 8, 2014, 3:11 PM

Bulk rejecting stale issues. If this is still a legitimate issue on ORM 4, feel free to comment and attach a test case. I'll address responses case-by-case. Thanks!

Rejected

Assignee

Unassigned

Reporter

e

Fix versions

None

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

Priority

Major