分页模板
select *
from (select *
from (select a.*, rownum rn
from (查询SQL) a)
where rownum <= 10)
where rn >= 1;
创建测试表
SYS@ora19c>create table t_page as select * from dba_objects;
Table created.
--注意所有列都是可为空的
SYS@ora19c> desc t_page;
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER VARCHAR2(128)
OBJECT_NAME VARCHAR2(128)
SUBOBJECT_NAME VARCHAR2(128)
OBJECT_ID NUMBER
DATA_OBJECT_ID NUMBER
OBJECT_TYPE VARCHAR2(23)
CREATED DATE
LAST_DDL_TIME DATE
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
NAMESPACE NUMBER
EDITION_NAME VARCHAR2(128)
SHARING VARCHAR2(18)
EDITIONABLE VARCHAR2(1)
ORACLE_MAINTAINED VARCHAR2(1)
APPLICATION VARCHAR2(1)
DEFAULT_COLLATION VARCHAR2(100)
DUPLICATED VARCHAR2(1)
SHARDED VARCHAR2(1)
CREATED_APPID NUMBER
CREATED_VSNID NUMBER
MODIFIED_APPID NUMBER
MODIFIED_VSNID NUMBER
下面5个例子中,需要将查询结果分页显示,每页显示10条。
例1:select * from t_page order by object_id;
没有过滤条件,只有排序。注意索引(位图索引除外)不保存全是null的记录。
create index IDX_T_PAGE_OBJ_ID on t_page(object_id,0);
select *
from (select t.*, rownum rn
from (select * from t_page order by object_id) t
where rownum <= 10)
where rn > = 1;
----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 10 |00:00:00.01 | 5 |
|* 1 | VIEW | | 1 | 10 | 4940 | 3 (0)| 00:00:01 | 10 |00:00:00.01 | 5 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 5 |
| 3 | VIEW | | 1 | 10 | 4810 | 3 (0)| 00:00:01 | 10 |00:00:00.01 | 5 |
| 4 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 26010 | 2946K| 3 (0)| 00:00:01 | 10 |00:00:00.01 | 5 |
| 5 | INDEX FULL SCAN | IDX_T_PAGE_OBJ_ID | 1 | 10 | | 2 (0)| 00:00:01 | 10 |00:00:00.01 | 3 |
----------------------------------------------------------------------------------------------------------------------------------------------
例2:select * from t_page where owner = 'SCOTT' order by object_id;
继续用例1创建的索引
select *
from (select t.*, rownum rn
from (select /*+ index(t_page IDX_T_PAGE_OBJ_ID)*/* from t_page where owner = 'SCOTT' order by object_id) t
where rownum <= 10)
where rn > = 1;
----------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 550 (100)| | 10 |00:00:00.01 | 659 |
|* 1 | VIEW | | 1 | 10 | 4940 | 550 (1)| 00:00:01 | 10 |00:00:00.01 | 659 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 659 |
| 3 | VIEW | | 1 | 10 | 4810 | 550 (1)| 00:00:01 | 10 |00:00:00.01 | 659 |
|* 4 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 10 | 1160 | 550 (1)| 00:00:01 | 10 |00:00:00.01 | 659 |
| 5 | INDEX FULL SCAN | IDX_T_PAGE_OBJ_ID | 1 | 26010 | | 55 (0)| 00:00:01 | 26007 |00:00:00.01 | 66 |
----------------------------------------------------------------------------------------------------------------------------------------------
应该在索引扫描时就得到10条数据,创建owner,object_id字段的联合索引
create index idx_t_page_owner_obj_id on t_page(owner,object_id,0);
select *
from (select t.*, rownum rn
from (select /*+ index(t_page idx_t_page_owner_obj_id)*/* from t_page where owner = 'SCOTT' order by object_id) t
where rownum <= 10)
where rn > = 1;
----------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 3 (100)| | 10 |00:00:00.01 | 6 |
|* 1 | VIEW | | 1 | 10 | 4940 | 3 (0)| 00:00:01 | 10 |00:00:00.01 | 6 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 6 |
| 3 | VIEW | | 1 | 10 | 4810 | 3 (0)| 00:00:01 | 10 |00:00:00.01 | 6 |
| 4 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 10 | 1160 | 3 (0)| 00:00:01 | 10 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | IDX_T_PAGE_OWNER_OBJ_ID | 1 | 12 | | 2 (0)| 00:00:01 | 10 |00:00:00.01 | 3 |
----------------------------------------------------------------------------------------------------------------------------------------------------
例3:select * from t_page order by object_id, object_name desc;
create index idx_t_page_obj_id_name on t_page(object_id, object_name desc,0);
select *
from (select *
from (select a.*, rownum rn
from (select /*+ index(t_page idx_t_page_obj_id_name)*/*
from t_page
order by object_id, object_name desc) a)
where rownum <= 10)
where rn >= 1;
-----------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 732 (100)| | 10 |00:00:00.01 | 5 |
|* 1 | VIEW | | 1 | 10 | 4940 | 732 (1)| 00:00:01 | 10 |00:00:00.01 | 5 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 5 |
| 3 | VIEW | | 1 | 26010 | 12M| 732 (1)| 00:00:01 | 10 |00:00:00.01 | 5 |
| 4 | COUNT | | 1 | | | | | 10 |00:00:00.01 | 5 |
| 5 | VIEW | | 1 | 26010 | 11M| 732 (1)| 00:00:01 | 10 |00:00:00.01 | 5 |
| 6 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 26010 | 2946K| 732 (1)| 00:00:01 | 10 |00:00:00.01 | 5 |
| 7 | INDEX FULL SCAN | IDX_T_PAGE_OBJ_ID_NAME | 1 | 26010 | | 139 (0)| 00:00:01 | 10 |00:00:00.01 | 3 |
-----------------------------------------------------------------------------------------------------------------------------------------------------
例4:select * from t_page where owner = 'SYS' and object_id > 1000 order by object_name;
按照索引创建ESR原则,字段顺序为等值(owner = 'SYS'),排序(order by object_name),范围(object_id > 1000)。
create index idx_owner_obj_name_obj_id on t_page(owner,object_name,object_id,0);
select *
from (select *
from (select a.*, rownum rn
from (select /*+ index(t_page idx_owner_obj_name_obj_id)*/*
from t_page
where owner = 'SYS'
and object_id > 1000
order by object_name) a)
where rownum <= 10)
where rn >= 1;
--------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 7201 (100)| | 10 |00:00:00.01 | 8 |
|* 1 | VIEW | | 1 | 10 | 4940 | 7201 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 8 |
| 3 | VIEW | | 1 | 14267 | 6882K| 7201 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
| 4 | COUNT | | 1 | | | | | 10 |00:00:00.01 | 8 |
| 5 | VIEW | | 1 | 14267 | 6701K| 7201 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
| 6 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 14267 | 1894K| 7201 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
|* 7 | INDEX RANGE SCAN | IDX_OWNER_OBJ_NAME_OBJ_ID | 1 | 14267 | | 89 (0)| 00:00:01 | 10 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------
例5:select * from t_page where owner like 'SYS%' and object_id > 1000 order by object_name;
create index idx_t_page_owner_obj_name_objid on t_page(object_name,owner,object_id,0);
select *
from (select *
from (select a.*, rownum rn
from (select /*+ index(t_page idx_t_page_owner_obj_name_objid)*/*
from t_page
where owner like 'SYS%'
and object_id > 1000
order by object_name) a)
where rownum <= 10)
where rn >= 1;
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 6817 (100)| | 10 |00:00:00.01 | 8 |
|* 1 | VIEW | | 1 | 10 | 4940 | 6817 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
|* 2 | COUNT STOPKEY | | 1 | | | | | 10 |00:00:00.01 | 8 |
| 3 | VIEW | | 1 | 14723 | 7102K| 6817 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
| 4 | COUNT | | 1 | | | | | 10 |00:00:00.01 | 8 |
| 5 | VIEW | | 1 | 14723 | 6915K| 6817 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
| 6 | TABLE ACCESS BY INDEX ROWID| T_PAGE | 1 | 14723 | 1955K| 6817 (1)| 00:00:01 | 10 |00:00:00.01 | 8 |
|* 7 | INDEX FULL SCAN | IDX_T_PAGE_OWNER_OBJ_NAME_OBJID | 1 | 14723 | | 155 (0)| 00:00:01 | 10 |00:00:00.01 | 3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------