简体   繁体   中英

Oracle Rownum SQL

What are the differences (advantages and disadvantages) between these two coding techniques?

select * from (
    select rownum rnun, * from table where rownum < x
) where rnum > y


select * from (
    select * from table
) where rownum < x and x > y

The two queries return different rows.

Neither query is deterministic. So neither query should ever be used in a real system.

The first query appears to be at least an attempt to generate a window of rows (rows between x and y). Since there is no ORDER BY, however, the order of rows is not deterministic and the window probably doesn't do what you want.

The second query returns an arbitrary x rows of data (assuming x > y). Otherwise it returns 0 rows (if y >= x). If you're trying to build some sort of windowing query, this isn't it.

If you want a windowing query that works, you'd want something like

SELECT *
  FROM (SELECT a.*,
               row_number() over (order by something) rnum
          FROM table_name)
 WHERE rnum BETWEEN x AND y

If you wanted to use ROWNUM, you'd need something like

SELECT *
  FROM (SELECT a.*,
               rownum rnum
          FROM( SELECT b.*
                  FROM table_name
                 ORDER BY something) a)
 WHERE rownum < y
   AND rnum > x

But this tends to be less efficient than the analytic query approach.

Besides the absence of the “order by” clause….. May be the question is about Oracle STOPKEY feature? In case of “paging” queries Oracle can use a STOPKEY feature to limit the number of rows in the subquery, this can lead to some performance gain.

Look at this query:

select *
  from (select a.*,
               row_number() over (order by sname) rnum
          from t_patient_card a)
 where rnum between 1 and 100           

                                                        Cost    Cardinality

SELECT STATEMENT, GOAL = FIRST_ROWS                     313272  3571266
 VIEW        HOSPITAL2$                                 313272  3571266
  SORT ORDER BY                                         313272  3571266
   COUNT
  TABLE ACCESS FULL    HOSPITAL2$    T_PATIENT_CARD     38883   3571266

Oracle fetched all the rows before is return only 100 of them

Let's rewrite the query like this:

select *
  from (
  select rownum as rn,tt.*  from  
  (
   select  t.* from t_patient_card t order by  t.sname
  )tt where rownum<100       
    ) 
 WHERE rn >1

In this case we user rownum<100 in the subquery to inform the optimizer that we want to get less the 100 rows.

                                                        Cost    Cardinality
SELECT STATEMENT, GOAL = ALL_ROWS                       313272  99
 VIEW    HOSPITAL2$                                     313272  99
  COUNT STOPKEY
   VIEW    HOSPITAL2$                                   313272  3571266
    SORT ORDER BY STOPKEY                               313272  3571266
  TABLE ACCESS FULL    HOSPITAL2$    T_PATIENT_CARD     38883   3571266

You can see the “count stopkey” and cardinality is only 99 after this step.In my database the second query executes one second faster then the first one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM