oracle分页的三种写法及其下推裁剪优化:
1) 从12c开始,分页有新的fetch,offset的语法,可以和order by写一起,内部使用row_number/rank分析函数实现,with ties用rank实现
2) row_number分析函数从oracle 11g后就做了优化,可以类似普通分页写法那样,满足条件可以下推裁剪,减少数据访问量
rank分析函数可以下推
注意:dense_rank不能走索引下推优化
3)传统rownum写法裁剪优化
12c fetch语法结构图:
-
SELECT column1, column2, ...
-
FROM table
-
[WHERE conditions]
-
[GROUP BY columns]
-
[HAVING conditions]
-
[ORDER BY columns [ASC | DESC]]
-
[OFFSET offset_value {ROW | ROWS}]
-
[FETCH {FIRST | NEXT} [num | percent PERCENT] {ROW | ROWS} {ONLY | WITH TIES}];
其中offset是从哪个位置开始,跳过这个位置,开始从下个位置获取
fetch后面的first和next其实一样,只不过如果获取前n行,使用fetch first 10 rows only可读性更新
offset 5 rows fetch next 10 rows可读性更强,next和offset连用可读性更强
row和rows随便,一般用rows,only也可以不用,with ties类似rank排名,使用with ties包含重复排名,行数不会变多:
-
select object_name,rn
-
from(
-
select object_name,row_number() over(order by object_id desc) rn
-
from b
-
) where rn<10;
从执行计划看ID=4,走索引的时候就裁剪了,只访问了10行:
-
Plan hash value: 1231498170
-
-
-------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
-------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 9 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 10 | 9 |00:00:00.01 | 5 |
-
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 9 | 10 |00:00:00.01 | 5 |
-
| 3 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 10 |00:00:00.01 | 5 |
-
| 4 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 9 | 10 |00:00:00.01 | 3 |
-
-------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("RN"<10)
-
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<10)
rank可下推,fetch with ties就用rank实现:
-
select object_name,rn from( select object_name,
-
rank() over(order by object_id desc) rn from b ) where rn<10;
可以看到从ID=4走索引裁剪:
-
Plan hash value: 1231498170
-
-
-------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
-------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 9 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 9 | 9 |00:00:00.01 | 5 |
-
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 9 | 10 |00:00:00.01 | 5 |
-
| 3 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 10 |00:00:00.01 | 5 |
-
| 4 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 9 | 10 |00:00:00.01 | 3 |
-
-------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("RN"<10)
-
2 - filter(RANK() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<10)
dense_rank不能走索引下推优化,从执行计划看走全表扫描:
-
select object_name,rn from( select object_name,
-
dense_rank() over(order by object_id desc) rn from b ) where rn<10;
-
-
SQL_ID 5tfy82nhgwn31, child number 0
-
-------------------------------------
-
select object_name,rn from( select object_name, dense_rank() over(order
-
by object_id desc) rn from b ) where rn<10
-
-
Plan hash value: 3571113929
-
-
----------------------------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-
----------------------------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 9 |00:00:00.03 | 1428 | | | |
-
|* 1 | VIEW | | 1 | 73318 | 9 |00:00:00.03 | 1428 | | | |
-
|* 2 | WINDOW SORT PUSHED RANK| | 1 | 73318 | 10 |00:00:00.03 | 1428 | 2675K| 740K| 2377K (0)|
-
| 3 | TABLE ACCESS FULL | B | 1 | 73318 | 73287 |00:00:00.01 | 1428 | | | |
-
----------------------------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("RN"<10)
-
2 - filter(DENSE_RANK() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<10)
分析函数分页的between and 写法也可以下推,先下推<=:
-
select object_name,rn from( select object_name,
-
row_number() over(order by object_id desc) rn from b ) where rn between 5 and 10;
-
-
SQL_ID f7vs81xvw5513, child number 0
-
-------------------------------------
-
select object_name,rn from( select object_name, row_number() over(order
-
by object_id desc) rn from b ) where rn between 5 and 10
-
-
Plan hash value: 1231498170
-
-
-------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
-------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 6 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 10 | 6 |00:00:00.01 | 5 |
-
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 10 | 10 |00:00:00.01 | 5 |
-
| 3 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 10 |00:00:00.01 | 5 |
-
| 4 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 10 | 10 |00:00:00.01 | 3 |
-
-------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter(("RN">=5 AND "RN"<=10))
-
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<=10)
传统rownum分页写法,如果只取top n,
必须是先排序,然后中间rownum<=并取rownum rn别名,然后rownum<
如果是between and ...必须三层嵌套,
{BANNED}最佳外层rn>...
-
select object_name,rn
-
from(
-
select object_name,rownum rn
-
from(
-
select object_name from b order by object_id desc
-
) where rownum<=10
-
) where rn >= 5;
-
-
Plan hash value: 3182714800
-
-
--------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
--------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 6 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 10 | 6 |00:00:00.01 | 5 |
-
|* 2 | COUNT STOPKEY | | 1 | | 10 |00:00:00.01 | 5 |
-
| 3 | VIEW | | 1 | 10 | 10 |00:00:00.01 | 5 |
-
| 4 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 10 |00:00:00.01 | 5 |
-
| 5 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 10 | 10 |00:00:00.01 | 3 |
-
--------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("RN">=5)
-
2 - filter(ROWNUM<=10)
使用12c新语法一样可以下推,实际上就是用分析函数实现的:
-
select object_name from b order by object_id desc offset 4 rows fetch next 6 rows only;
-
Plan hash value: 1231498170
-
-
-------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
-------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 6 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 10 | 6 |00:00:00.01 | 5 |
-
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 10 | 10 |00:00:00.01 | 5 |
-
| 3 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 10 |00:00:00.01 | 5 |
-
| 4 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 10 | 10 |00:00:00.01 | 3 |
-
-------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter(("from$_subquery$_002"."rowlimit_$$_rownumber"<=10 AND
-
"from$_subquery$_002"."rowlimit_$$_rownumber">4))
-
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<=10)
with ties,可能返回多于5行,用rank实现,可以下推:
-
select object_name from b order by object_id desc fetch first 5 rows with ties;
-
-
Plan hash value: 1231498170
-
-
-------------------------------------------------------------------------------------------------
-
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-
-------------------------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 1 | | 5 |00:00:00.01 | 5 |
-
|* 1 | VIEW | | 1 | 5 | 5 |00:00:00.01 | 5 |
-
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 5 | 5 |00:00:00.01 | 5 |
-
| 3 | TABLE ACCESS BY INDEX ROWID| B | 1 | 73318 | 5 |00:00:00.01 | 5 |
-
| 4 | INDEX FULL SCAN DESCENDING| IDX_B | 1 | 5 | 5 |00:00:00.01 | 3 |
-
-------------------------------------------------------------------------------------------------
-
-
Predicate Information (identified by operation id):
-
---------------------------------------------------
-
-
1 - filter("from$_subquery$_002"."rowlimit_$$_rank"<=5)
-
2 - filter(RANK() OVER ( ORDER BY INTERNAL_FUNCTION("OBJECT_ID") DESC )<=5)