oracle更快的分页查询

Pat*_*eon 10 oracle

我有两个我考虑使用的分页查询.

第一个是

SELECT * FROM ( SELECT rownum rnum, a.* from (
    select * from members
) a WHERE rownum <= #paging.endRow# ) where rnum > #paging.startRow#
Run Code Online (Sandbox Code Playgroud)

第二是

SELECT * FROM ( SELECT rownum rnum, a.* from (
    select * from members
) a ) WHERE rnum BETWEEN #paging.startRow# AND #paging.endRow#
Run Code Online (Sandbox Code Playgroud)

您如何看待哪个查询更快?

Ale*_*ssi 15

我现在实际上没有Oracle的可用性,但是对于分页的最佳SQL查询肯定是以下内容

select *
from (
        select rownum as rn, a.*
        from (
                select *
                from my_table
                order by ....a_unique_criteria...
            ) a
    )
where rownum <= :size
    and rn >  (:page-1)*:size
Run Code Online (Sandbox Code Playgroud)

http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html

要实现一致的分页,您应该使用唯一标准对行进行排序,这样可以避免为页面X加载已为页面Y加载的行(!= X).


GWu*_*GWu 9

看一下执行计划,例如1000行:

SELECT *
  FROM (SELECT ROWNUM rnum
              ,a.*
          FROM (SELECT *
                  FROM members) a
         WHERE ROWNUM <= endrow#)
 WHERE rnum > startrow#;

--------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |         |  1000 | 39000 |     3   (0)| 00:00:01 |
|*  1 |  VIEW                |         |  1000 | 39000 |     3   (0)| 00:00:01 |
|   2 |   COUNT              |         |       |       |            |          |
|*  3 |    FILTER            |         |       |       |            |          |
|   4 |     TABLE ACCESS FULL| MEMBERS |  1000 | 26000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RNUM">"STARTROW#")
   3 - filter("MEMBERS"."ENDROW#">=ROWNUM)
Run Code Online (Sandbox Code Playgroud)

2.

SELECT *
  FROM (SELECT ROWNUM rnum
              ,a.*
          FROM (SELECT *
                  FROM members) a)
 WHERE rnum BETWEEN startrow# AND endrow#;

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |  1000 | 39000 |     3   (0)| 00:00:01 |
|*  1 |  VIEW               |         |  1000 | 39000 |     3   (0)| 00:00:01 |
|   2 |   COUNT             |         |       |       |            |          |
|   3 |    TABLE ACCESS FULL| MEMBERS |  1000 | 26000 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RNUM"<="ENDROW#" AND "RNUM">="STARTROW#")
Run Code Online (Sandbox Code Playgroud)

除此之外,我认为版本2 可能会稍快一些,因为它包含的步骤少了一步.但我不知道您的索引和数据分布,因此您可以自己获取这些执行计划并判断数据的情况.或者只是测试它.