Oracle优化之单表分页优化

单表分页优化思路:

--创建测试表:

SQL> create table t_test as select * from dba_objects;

Table created.

如,下面的sql (没有过滤条件,只有排序),要将查询结果分页显示,每页显示10条,如:

select * from t_test order by object_id;

例子:

1、分页查询sql语句,如下(通常会采用下面的方法,但是这是错误的分页框架)

语法:select * from (select t.*,rownum rn from (需要分页的sql)t ) where rn >=1 and rn <=10;

SQL> select * from (select t.*,rownum rn from (select * from t_test order by object_id) t) where rn >=1 and rn <=10;
Execution Plan
----------------------------------------------------------
Plan hash value: 3603170480
----------------------------------------------------------------------------------------
| Id  | Operation            | Name  | Rows  | Bytes |TempSpc| Cost (%CPU)| Time    |
----------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT      |        | 80700 |    16M|      |  3918  (1)| 00:00:48 |
|*  1 |  VIEW                |        | 80700 |    16M|      |  3918  (1)| 00:00:48 |
|  2 |  COUNT              |        |      |      |      |            |          |
|  3 |    VIEW              |        | 80700 |    15M|      |  3918  (1)| 00:00:48 |
|  4 |    SORT ORDER BY    |        | 80700 |    15M|    19M|  3918  (1)| 00:00:48 |
|  5 |      TABLE ACCESS FULL| t_test | 80700 |    15M|      |  287  (1)| 00:00:04 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
  1 - filter("RN"<=10 AND "RN">=1)
Note
-----
  - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
        331  recursive calls
          0  db block gets
      1211  consistent gets
      1024  physical reads
          0  redo size
      2075  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
        10  rows processed

从上面的执行计划可以看出,该sql走了全表扫描,如果该表很大,则先要将该表排序,再取出其中10行数据,这样会出现严重的性能问题,所以该sql不能走全表扫描,必须走索引扫描。(因为索引已经排序了,可使用索引来消除排序)一般分页语句中都有排序。

如下,在object_id列建立索引,并在索引中添加一个常量0,如下:(在索引中添加一个常量0,是因为object_id列允许位null,如果不添加常量(不一定是0,可以是1,2,3,也可以是英文字母),索引中就不能存储null值,;因为sql中并没有剔除null值,所以我们必须要添加一个常量,让索引存储null,这样才能使sql走索引。)

SQL> create index idx_test on t_test(object_id,0);

SQL> select * from (select t.*,rownum rn from (select /*+ index)t_test idx_test) */ * from t_test order by object_id) t) where rn >=1 and rn <=10;

SQL> alter session set statistics_level=all;

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
-----------------------------------------
SQL_ID  gvq2rvmutr85w, child number 0
-------------------------------------
 select * from (select t.*,rownum rn from (select /*+ index)t_test
idx_test) */ * from t_test order by object_id) t) where rn >=1 and rn
<=10
Plan hash value: 3119682446
-----------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name    | Starts | E-Rows | A-Rows |  A-Time  | Buffers |
-----------------------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT              |          |      1 |        |    10 |00:00:00.08 |    1245 |
|*  1 |  VIEW                          |          |      1 |  80700 |    10 |00:00:00.08 |    1245 |
|  2 |  COUNT                        |          |      1 |        |  71903 |00:00:00.07 |    1245 |
|  3 |    VIEW                        |          |      1 |  80700 |  71903 |00:00:00.06 |    1245 |
|  4 |    TABLE ACCESS BY INDEX ROWID| t_test  |      1 |  80700 |  71903 |00:00:00.04 |    1245 |
|  5 |      INDEX FULL SCAN          | IDX_test |      1 |  80700 |  71903 |00:00:00.01 |    181 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
  1 - filter(("RN"<=10 AND "RN">=1))
Note
-----
  - dynamic sampling used for this statement (level=2)
28 rows selected.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/54dde0eed17e5e61c9154771a785f4c8.html