今天总结一下分页查询,下面几个链接是yangtingkun blog上的测试,写的很详细!
Oracle分页查询语句(1)
[url]http://yangtingkun.itpub.net/post/468/100278[/url]
Oracle分页查询语句(2)
[url]http://yangtingkun.itpub.net/post/468/101703[/url]
Oracle分页查询语句(3)
[url]http://yangtingkun.itpub.net/post/468/104595[/url]
Oracle分页查询语句(4)
[url]http://yangtingkun.itpub.net/post/468/104867[/url]
下面是对优化的进一步总结和补充:
首先,创建测试表
create table t2 as select * from dba_objects;
create idx idx-t2 on t2(object_id);
最早使用分页方法:
SQL> set autotrace on
SQL> /
RN OBJECT_ID OBJECT_NAME
---------- ---------- ----------------------------------------------------------
96 97 ACCESS$
97 98 AUD$
98 99 LINK$
99 100 TRUSTED_LIST$
100 101 PROPS$
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 VIEW
2 1 COUNT
3 2 VIEW
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'T2'
5 4 INDEX (RANGE SCAN) OF 'IDX_T2' (NON-UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
346 consistent gets
0 physical reads
0 redo size
604 bytes sent via SQL*Net to client
504 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5 rows processed
我们发现,逻辑读为346 ,做第一次改进,将rn<=100移到第二层循环:
SQL> select rn,object_id,object_name from
2 (
3 select rownum rn,a.* from
4 (
5 select * from t2 where object_id<500 order by object_id
6 ) a where rownum<100
7 )
8 where rn>95;
RN OBJECT_ID OBJECT_NAME
---------- ---------- ----------------------------------------------------------
96 97 ACCESS$
97 98 AUD$
98 99 LINK$
99 100 TRUSTED_LIST$
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 VIEW
2 1 COUNT (STOPKEY)
3 2 VIEW
4 3 TABLE ACCESS (BY INDEX ROWID) OF 'T2'
5 4 INDEX (RANGE SCAN) OF 'IDX_T2' (NON-UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
63 consistent gets
0 physical reads
0 redo size
585 bytes sent via SQL*Net to client
504 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed
我们发现,逻辑读降到了63,执行计划中用到了stopkey,也就是排序的时候只排到前100条就停止。
上面的改进中我们发现,排序虽然只排到了前100个,但是仍然有95条记录是做的无用功(因为只输出5条记录),这样,翻的页数越大,做的无用功越多,效率自然也越低,这时,我们可以做进一步的改进:
SQL> select rn,t2.object_id,object_name from t2,
2 (
3 select * from
4 (
5 select rownum rn,a.* from
6 (
7 select rowid rd,object_id from t2 where object_id<500 order by object_id
8 ) a where rownum<100
9 ) where rn>95
10 )c
11 where t2.rowid=c.rd;
RN OBJECT_ID OBJECT_NAME
---------- ---------- ----------------------------------------------------------
96 97 ACCESS$
97 98 AUD$
98 99 LINK$
99 100 TRUSTED_LIST$
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 VIEW
3 2 COUNT (STOPKEY)
4 3 VIEW
5 4 INDEX (RANGE SCAN) OF 'IDX_T2' (NON-UNIQUE)
6 1 TABLE ACCESS (BY USER ROWID) OF 'T2'
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
585 bytes sent via SQL*Net to client
504 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed
此时,我们直接对索引进行排序后的提取,然后用rowid和原表进行表关联,因为索引是拍好序的,因此对索引的rowid的提取非常快,提取出的 rowid和原表做nested loop也非常快(rowid查询是最快的方法),因此,我们发现,逻辑读居然降到了只有7,大大提高了分页的查询速度。