ROW_NUMBER
is quite inefficient in Oracle
.
See the article in my blog for performance details:
For your specific query, I'd recommend you to replace it with ROWNUM
and make sure that the index is used:
SELECT *
FROM (
SELECT /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
t.*, ROWNUM AS rn
FROM table t
ORDER BY
column
)
WHERE rn >= :start
AND rownum <= :end - :start + 1
This query will use COUNT STOPKEY
Also either make sure you column
is not nullable, or add WHERE column IS NOT NULL
condition.
Otherwise the index cannot be used to retrieve all values.
Note that you cannot use ROWNUM BETWEEN :start and :end
without a subquery.
ROWNUM
is always assigned last and checked last, that's way ROWNUM
's always come in order without gaps.
If you use ROWNUM BETWEEN 10 and 20
, the first row that satisifies all other conditions will become a candidate for returning, temporarily assigned with ROWNUM = 1
and fail the test of ROWNUM BETWEEN 10 AND 20
.
Then the next row will be a candidate, assigned with ROWNUM = 1
and fail, etc., so, finally, no rows will be returned at all.
This should be worked around by putting ROWNUM
's into the subquery.