Oracle efficient paging query summary

Reference link for this article: http://blog.sina.com.cn/s/blog_8604ca230100vro9.html

Explore the query statement:

copy code
-- Paging parameters: size = 20 page = 2
--Query without order by
-- Nested subqueries, filter twice (recommended)
--SELECT *
-- FROM (SELECT ROWNUM AS rowno, t.*
-- FROM DONORINFO t
-- WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
-- AND TO_DATE ('20060731', 'yyyymmdd')
-- AND ROWNUM <= 20*2) table_alias
-- WHERE table_alias.rowno > 20*(2-1); -- takes 0.05s

-- One-time filtering (when the amount of data is large, the amount of data queried for the first time is too large, which is obviously slower than the above, not recommended)
--select * from(
--SELECT ROWNUM AS rowno, t.*
--FROM DONORINFO t
--WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd') AND TO_DATE ('20060731', 'yyyymmdd')
--) r
--where r.rowno BETWEEN 20*(2-1)+1 and 20*2;      --耗时0.46s


--Query with order by
-- Nested subqueries, filter twice (recommended)
--SELECT *
--FROM (SELECT ROWNUM AS rowno,r.*
-- FROM(
-- SELECT * FROM DONORINFO t
-- WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
-- AND TO_DATE ('20060731', 'yyyymmdd')
-- ORDER BY t.BIRTHDAY desc
-- ) r
-- where ROWNUM <= 20*2
-- ) table_alias
-- WHERE table_alias.rowno > 20*(2-1); -- takes 0.744s

-- One-time filtering (when the amount of data is large, the amount of data queried for the first time is too large, which is obviously slower than the above, not recommended)
--select * from (
--SELECT ROWNUM AS rowno,r.*
--FROM(
--SELECT * FROM DONORINFO t
--WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
--AND TO_DATE ('20060731', 'yyyymmdd')
--ORDER BY t.BIRTHDAY desc
--) r
----where ROWNUM <= 20; -- here use > can not find data = can not find data <= or < can find data
----where ROWNUM BETWEEN 20*(2-1)+1 AND 20*2; --No data found
----where ROWNUM <=20*2 and ROWNUM > 20*(2-1); --No data found
---- This is because the first rownum generated by the query is 1, 1>20 does not hold, and 1=20 does not hold, so this data is invalid, and so on, so that no data can be found.
--) t
--where t.rowno <=20*2 and t.rowno > 20*(2-1); --Time to find data: 3.924s
---- where t.rowno BETWEEN 20*(2-1)+1 AND 20*2; -- time to find the data: 3.919s

--Use row_number() over paging function
--select *
--from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber
--     from DONORINFO d
--     WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
--                             AND TO_DATE ('20060731', 'yyyymmdd')
-- ) p
--where p.rownumber BETWEEN 20*(2-1)+1 AND 20*2;  --耗时0.812s

select * from (
select *
from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber
     from DONORINFO d
     WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
                             AND TO_DATE ('20060731', 'yyyymmdd')
 ) p
where p.rownumber <20*2
) where rownumber > 20*(2-1); -- takes 0.813s
copy code

 

From the above exploration and comparison, we know that:

1、ROWNUM

  The rownum always starts from 1. If the first row is not satisfied, the rownum of the second row becomes 1 again. And so on, so there is never a record that meets the condition.

    It can be understood this way: rownum is a sequence, which is the order in which the Oracle database reads data from the data file or buffer.

    It gets the rownum value of 1 for the first record and 2 for the second. And so on.

    When using the conditions of ">, >=, =, between...and", the rownum of the first record obtained from the buffer or data file is 1, which does not meet the conditions of the SQL statement and will be deleted, and then Remove the bar.

    The rownum of the next item will still be 1, and it will be deleted, and so on, and there will be no data.

  Therefore, the upper limit condition must be placed in the subquery, and the lower limit condition must be placed in the outer query.

2、between  and 和 >= and <=

There is no difference in query efficiency between the two, and between and is eventually converted to >= and <=

所以select * from (select * from a where a.time >= to_date('19920324','yyyymmdd')) b where b.time <= to_date('20170324','yyyymmdd')

Such nesting is not necessary, you can use between and directly.

3. Oracle general paging format

For pagination without order by statement:

copy code
SELECT *
FROM (SELECT ROWNUM AS rowno, t.*
          FROM DONORINFO t
          WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
          AND TO_DATE ('20060731', 'yyyymmdd')
          AND ROWNUM <= page*size) table_alias
WHERE table_alias.rowno > (page-1)*size;    
copy code
SELECT *
FROM (SELECT ROWNUM AS rowno, t.*
          FROM BDC_XM t        
          where ROWNUM <= 100) a
WHERE a.rowno > 80;   

Pagination with order by statement

copy code
SELECT *
FROM (SELECT ROWNUM AS rowno,r.*
           FROM(SELECT * FROM DONORINFO t
                    WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
                    AND TO_DATE ('20060731', 'yyyymmdd')
                    ORDER BY t.BIRTHDAY desc
                   ) r
           where ROWNUM <= page*size
          ) table_alias
WHERE table_alias.rowno > (page-1)*size;
copy code

Alternatively we can use the row_number() over function:

copy code
select *
from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber
       from DONORINFO d
       WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
        AND TO_DATE ('20060731', 'yyyymmdd')
 ) p
where p.rownumber BETWEEN size*(page-1)+1 AND page*size;
copy code

But there is no advantage over the previous one.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325065359&siteId=291194637