技术开发 频道

使用SQL对记录进行分页的3种方式

  【IT168 技术】1、通常的分页写法,也是第一种分页方法,类似如下方式:

  select * from (

  select a.*, rownum rn from

  (select * from test a order by object_name) a

  where rownum <=1000)

  where rn > 990;

  这种方式,是对表进行排序翻页,比较常见,但是,第一页与第1000页的性能差异还是挺明显的。

  2、第二种的分页写法是对索引进行翻页操作,然后根据rowid 去表中取数据。 这种方式,第一页与第1000页性能相差不大。

  以下语句虽然使用HINT指定使用索引, 但是仍然没有生效。

  select b.* from (

  select * from (

  select a.*, rownum rn from

  (select /*+ index(a ix_object_name) */ rowid rid from test a order by object_name) a

  where rownum <=20)

  where rn > 10) a, test b

  where a.rid = b.rowid;

  Elapsed: 00:00:00.01

  Execution Plan

  ----------------------------------------------------------

  Plan hash value: 1616265646

  --------------------------------------------------------------------------------------------

  | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

  --------------------------------------------------------------------------------------------

  | 0 | SELECT STATEMENT | | 20 | 2420 | | 319 (1)| 00:00:04 |

  | 1 | NESTED LOOPS | | 20 | 2420 | | 319 (1)| 00:00:04 |

  |* 2 | VIEW | | 20 | 500 | | 299 (1)| 00:00:04 |

  |* 3 | COUNT STOPKEY | | | | | | |

  | 4 | VIEW | | 23713 | 277K| | 299 (1)| 00:00:04 |

  |* 5 | SORT ORDER BY STOPKEY | | 23713 | 741K| 944K| 299 (1)| 00:00:04 |

  | 6 | TABLE ACCESS FULL | TEST | 23713 | 741K| | 89 (0)| 00:00:02 |

  | 7 | TABLE ACCESS BY USER ROWID| TEST | 1 | 96 | | 1 (0)| 00:00:01 |

  --------------------------------------------------------------------------------------------

  Predicate Information (identified by operation id):

  ---------------------------------------------------

  2 - filter("RN">10)

  3 - filter(ROWNUM<=20)

  5 - filter(ROWNUM<=20)

  Statistics

  ----------------------------------------------------------

  0 recursive calls

  0 db block gets

  327 consistent gets

  0 physical reads

  0 redo size

  2032 bytes sent via SQL*Net to client

  520 bytes received via SQL*Net from client

  2 SQL*Net roundtrips to/from client

  1 sorts (memory)

  0 sorts (disk)

  10 rows processed

  添加not null 约束之后,就使用索引了。

  SQL> alter table test modify object_name not null;

  Table altered.

  Elapsed: 00:00:00.02

  SQL> select b.* from (

  2 select * from (

  3 select a.*, rownum rn from

  4 (select /*+ index(a ix_object_name) */ rowid rid from test a order by object_name) a

  5 where rownum <=20)

  6 where rn > 10) a, test b

  7 where a.rid = b.rowid;

  10 rows selected.

  Elapsed: 00:00:00.01

  Execution Plan

  ----------------------------------------------------------

  Plan hash value: 2741793364

  ----------------------------------------------------------------------------------------------

  | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

  ----------------------------------------------------------------------------------------------

  | 0 | SELECT STATEMENT | | 20 | 2420 | 22 (0)| 00:00:01 |

  | 1 | NESTED LOOPS | | 20 | 2420 | 22 (0)| 00:00:01 |

  |* 2 | VIEW | | 20 | 500 | 2 (0)| 00:00:01 |

  |* 3 | COUNT STOPKEY | | | | | |

  | 4 | VIEW | | 20 | 240 | 2 (0)| 00:00:01 |

  | 5 | INDEX FULL SCAN | IX_OBJECT_NAME | 20 | 640 | 2 (0)| 00:00:01 |

  | 6 | TABLE ACCESS BY USER ROWID| TEST | 1 | 96 | 1 (0)| 00:00:01 |

  ----------------------------------------------------------------------------------------------

  Predicate Information (identified by operation id):

  ---------------------------------------------------

  2 - filter("RN">10)

  3 - filter(ROWNUM<=20)Statistics

  ----------------------------------------------------------

  1 recursive calls

  0 db block gets

  5 consistent gets

  0 physical reads

  0 redo size

  2032 bytes sent via SQL*Net to client

  520 bytes received via SQL*Net from client

  2 SQL*Net roundtrips to/from client

  0 sorts (memory)

  0 sorts (disk)

  10 rows processed

  最后几页: 这种方式还不如全表扫描的方式:

  select b.* from (

  select * from (

  select a.*, rownum rn from

  (select rowid rid from test a order by object_name) a

  where rownum <=20000)

  where rn > 19990) a, test b

  where a.rid = b.rowid;

  10 rows selected.

  Elapsed: 00:00:00.02

  Execution Plan

  ----------------------------------------------------------

  Plan hash value: 221961112

  --------------------------------------------------------------------------------------

  | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

  --------------------------------------------------------------------------------------

  | 0 | SELECT STATEMENT | | 20000 | 2363K| 179 (1)| 00:00:03 |

  |* 1 | HASH JOIN | | 20000 | 2363K| 179 (1)| 00:00:03 |

  |* 2 | VIEW | | 20000 | 488K| 89 (0)| 00:00:02 |

  |* 3 | COUNT STOPKEY | | | | | |

  | 4 | VIEW | | 20000 | 234K| 89 (0)| 00:00:02 |

  | 5 | INDEX FULL SCAN| IX_OBJECT_NAME | 23713 | 741K| 89 (0)| 00:00:02 |

  | 6 | TABLE ACCESS FULL | TEST | 23713 | 2223K| 90 (2)| 00:00:02 |

  --------------------------------------------------------------------------------------

  Predicate Information (identified by operation id):

  ---------------------------------------------------

  1 - access("from$_subquery$_002"."RID"="B".ROWID)

  2 - filter("RN">19990)

  3 - filter(ROWNUM<=20000)

  Statistics

  ----------------------------------------------------------

  1 recursive calls

  0 db block gets

  415 consistent gets

  0 physical reads

  0 redo size

  2040 bytes sent via SQL*Net to client

  520 bytes received via SQL*Net from client

  2 SQL*Net roundtrips to/from client

  0 sorts (memory)

  0 sorts (disk)

  10 rows processed

  SQL> select * from (

  2 select a.*, rownum rn from

  3 (select * from test a order by object_name) a

  4 where rownum <=20000)

  5 where rn > 19990;

  10 rows selected.

  Elapsed: 00:00:00.05

  Execution Plan

  ----------------------------------------------------------

  Plan hash value: 2340039655

  -----------------------------------------------------------------------------------------

  | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |

  -----------------------------------------------------------------------------------------

  | 0 | SELECT STATEMENT | | 20000 | 4296K| | 613 (1)| 00:00:08 |

  |* 1 | VIEW | | 20000 | 4296K| | 613 (1)| 00:00:08 |

  |* 2 | COUNT STOPKEY | | | | | | |

  | 3 | VIEW | | 23713 | 4793K| | 613 (1)| 00:00:08 |

  |* 4 | SORT ORDER BY STOPKEY| | 23713 | 2223K| 3120K| 613 (1)| 00:00:08 |

  | 5 | TABLE ACCESS FULL | TEST | 23713 | 2223K| | 90 (2)| 00:00:02 |

  -----------------------------------------------------------------------------------------

  Predicate Information (identified by operation id):

  ---------------------------------------------------

  1 - filter("RN">19990)

  2 - filter(ROWNUM<=20000)

  4 - filter(ROWNUM<=20000)

  Statistics

  ----------------------------------------------------------

  1 recursive calls

  0 db block gets

  325 consistent gets

  0 physical reads

  0 redo size

  2161 bytes sent via SQL*Net to client

  520 bytes received via SQL*Net from client

  2 SQL*Net roundtrips to/from client

  1 sorts (memory)

  0 sorts (disk)

  10 rows processed

  不应该啊! 全索引扫描不会比全表扫描性能更差吧。

  原来,以上性能差的原因是因为使用了hash join 方式, 我们指定使用NL方式看一下:

  select /*+ use_nl(a b) */ b.* from (

  select * from (

  select a.*, rownum rn from

  (select rowid rid from test a order by object_name) a

  where rownum <=20000)

  where rn > 19990) a, test b

  where a.rid = b.rowid;

  10 rows selected.

  Elapsed: 00:00:00.02

  Execution Plan

  ----------------------------------------------------------

  Plan hash value: 2741793364

  ----------------------------------------------------------------------------------------------

  | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

  ----------------------------------------------------------------------------------------------

  | 0 | SELECT STATEMENT | | 20000 | 2363K| 20097 (1)| 00:04:02 |

  | 1 | NESTED LOOPS | | 20000 | 2363K| 20097 (1)| 00:04:02 |

  |* 2 | VIEW | | 20000 | 488K| 89 (0)| 00:00:02 |

  |* 3 | COUNT STOPKEY | | | | | |

  | 4 | VIEW | | 20000 | 234K| 89 (0)| 00:00:02 |

  | 5 | INDEX FULL SCAN | IX_OBJECT_NAME | 23713 | 741K| 89 (0)| 00:00:02 |

  | 6 | TABLE ACCESS BY USER ROWID| TEST | 1 | 96 | 1 (0)| 00:00:01 |

  ----------------------------------------------------------------------------------------------

  Predicate Information (identified by operation id):

  ---------------------------------------------------

  2 - filter("RN">19990)

  3 - filter(ROWNUM<=20000)

  Statistics

  ----------------------------------------------------------

  1 recursive calls

  0 db block gets

  92 consistent gets

  0 physical reads

  0 redo size

  2049 bytes sent via SQL*Net to client

  520 bytes received via SQL*Net from client

  2 SQL*Net roundtrips to/from client

  0 sorts (memory)

  0 sorts (disk)

  10 rows processed

0
相关文章