• 分页语句优化


    技巧3:分页语句优化
    
    分页语句,一般都有order by column desc/asc
    
    分页语句的优化技巧:
    
    1.分页SQL要想快最好走索引,根据order by asc/desc ,用hint index_asc/index_desc 
      强制它走索引INDEX FULL SCAN  DESCENDING/INDEX RANGE SCAN DESCENDING
    
    2.不要让Oracle扫描整个index,确保只扫描一部分索引块,然后回表就取得数据,然后
      就count stopkey
    
    3.一定要确保索引回表的时候不要在表上再去过滤,也就是说TABLE ACCESS BY INDEX ROWID
      上面没*,不然就可能扫描整个索引块,根据where条件可以创建组合索引
      (分区表要创建global index)
    
    4.看执行计划的时候不要被执行计划的基数给骗了----它可能显示是有误差的
    
    分页方法:
    
    1.rownum 
    2.row_number over(order by column) as 行号
    
    例子:
    
    create table page as select * from dba_objects;
    create index idx_page on page(object_id);
    create index idx_page_1 on page(owner,object_id);
    create index idx_page_2 on page(owner);
    create index idx_page_3 on page(object_id,owner);
    BEGIN
      DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'SCOTT',
                                    tabname          => 'PAGE',
                                    estimate_percent => 100,
                                    method_opt       => 'for all columns size skewonly',
                                    no_invalidate    => FALSE,
                                    degree           => 4,
                                    cascade          => TRUE);
    END;
    /
    
    比如这个SQL
    
    select * from 
    (
    select * from 
    (
    select  a.*,rownum rn
      from page a 
     where object_id >1000 and owner='SYS'
     order by object_id desc
    ) where rownum<=20
    ) where rn>=0;
    看下高级执行计划:
    hr@JSSPDG>  select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    SQL_ID	6c4km249bgfc0, child number 1
    -------------------------------------
    select * from ( select * from ( select	a.*,rownum rn	from page a  where object_id >1000 and owner='SYS'
    order by object_id desc ) where rownum<=20 ) where rn>=0
    
    Plan hash value: 824209635
    
    ----------------------------------------------------------------------------------------------------------------------
    | Id  | Operation		 | Name | Starts | E-Rows | A-Rows |   A-Time	| Buffers |  OMem |  1Mem | Used-Mem |
    ----------------------------------------------------------------------------------------------------------------------
    |*  1 |  VIEW			 |	|      1 |     20 |	20 |00:00:03.49 |     700 |	  |	  |	     |
    |*  2 |   COUNT STOPKEY 	 |	|      1 |	  |	20 |00:00:03.49 |     700 |	  |	  |	     |
    |   3 |    VIEW 		 |	|      1 |  22611 |	20 |00:00:03.49 |     700 |	  |	  |	     |
    |*  4 |     SORT ORDER BY STOPKEY|	|      1 |  22611 |	20 |00:00:03.49 |     700 |  1207K|   570K| 1072K (0)|
    |   5 |      COUNT		 |	|      1 |	  |  22144 |00:00:02.68 |     700 |	  |	  |	     |
    |*  6 |       TABLE ACCESS FULL  | PAGE |      1 |  22611 |  22144 |00:00:01.15 |     700 |	  |	  |	     |
    ----------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN">=0)
       2 - filter(ROWNUM<=20)
       4 - filter(ROWNUM<=20)
       6 - filter(("OWNER"='SYS' AND "OBJECT_ID">1000))
    
    
    26 rows selected.
    
    
    Statistics
    ----------------------------------------------------------
    	  0  recursive calls
    	  0  db block gets
    	700  consistent gets
    	  0  physical reads
    	  0  redo size
           2919  bytes sent via SQL*Net to client
    	396  bytes received via SQL*Net from client
    	  3  SQL*Net roundtrips to/from client
    	  1  sorts (memory)
    	  0  sorts (disk)
    	 20  rows processed
    
    因为OWNER='SYS' 以及OBJECT_ID>1000 选择性都很低,ORACLE走的是全表扫描,分页语句绝对不能让它走全表扫描,现在加个HINT
    
    
    
    hr@JSSPDG> select * from ( select * from ( select /*+ index(a) */ a.*,rownum rn   from page a  where object_id >1000 and owner='SYS'
    order by object_id desc ) where rownum<=20 ) where rn>=0;
    
    
    Plan hash value: 4010810952
    
    ------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation			 | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
    ------------------------------------------------------------------------------------------------------------------------------------
    |*  1 |  VIEW				 |	      |      1 |     20 |     20 |00:00:08.34 |     627 |	|	|	   |
    |*  2 |   COUNT STOPKEY 		 |	      |      1 |	|     20 |00:00:08.34 |     627 |	|	|	   |
    |   3 |    VIEW 			 |	      |      1 |  22611 |     20 |00:00:08.33 |     627 |	|	|	   |
    |*  4 |     SORT ORDER BY STOPKEY	 |	      |      1 |  22611 |     20 |00:00:08.33 |     627 |  1207K|   570K| 1072K (0)|
    |   5 |      COUNT			 |	      |      1 |	|  22144 |00:00:07.47 |     627 |	|	|	   |
    |*  6 |       TABLE ACCESS BY INDEX ROWID| PAGE       |      1 |  22611 |  22144 |00:00:05.99 |     627 |	|	|	   |
    |*  7 |        INDEX RANGE SCAN 	 | IDX_PAGE_2 |      1 |  23035 |  23035 |00:00:02.15 |      51 |	|	|	   |
    ------------------------------------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN">=0)
       2 - filter(ROWNUM<=20)
       4 - filter(ROWNUM<=20)
       6 - filter("OBJECT_ID">1000)
       7 - access("OWNER"='SYS')
    
    
    
    Statistics
    ----------------------------------------------------------
    	  0  recursive calls
    	  0  db block gets
    	627  consistent gets
    	  0  physical reads
    	  0  redo size
           2919  bytes sent via SQL*Net to client
    	396  bytes received via SQL*Net from client
    	  3  SQL*Net roundtrips to/from client
    	  1  sorts (memory)
    	  0  sorts (disk)
    	 20  rows processed
    
    加了INDEX HINT之后,ORACLE走的是INDEX RANGE SCAN,但是INDEX RANGE SCAN选了23035 条数据,而不是只选择20条就停止,显然不是最优化的
    现在加上INDEX_DESC HINT
    
    select * from ( select * from ( select /*+ index_desc(a idx_page_3) */ a.*,rownum rn   from page
    a  where object_id >1000 and owner='SYS'  order by object_id desc ) where rownum<=20 ) where
    rn>=0
    
    Plan hash value: 3526010999
    
    ---------------------------------------------------------------------------------------------------------
    | Id  | Operation			 | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
    ---------------------------------------------------------------------------------------------------------
    |*  1 |  VIEW				 |	      |      1 |     20 |     20 |00:00:00.01 |       8 |
    |*  2 |   COUNT STOPKEY 		 |	      |      1 |	|     20 |00:00:00.01 |       8 |
    |   3 |    VIEW 			 |	      |      1 |  22611 |     20 |00:00:00.01 |       8 |
    |   4 |     COUNT			 |	      |      1 |	|     20 |00:00:00.01 |       8 |
    |   5 |      TABLE ACCESS BY INDEX ROWID | PAGE       |      1 |  22611 |     20 |00:00:00.01 |       8 |
    |*  6 |       INDEX RANGE SCAN DESCENDING| IDX_PAGE_3 |      1 |  22611 |     20 |00:00:00.01 |       4 |
    ---------------------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("RN">=0)
       2 - filter(ROWNUM<=20)
       6 - access("OBJECT_ID" IS NOT NULL AND "OBJECT_ID">1000 AND "OWNER"='SYS')
           filter("OWNER"='SYS')
    
    create index idx_page_3 on page(object_id,owner);
    
    create index idx_page on page(object_id);
    27 rows selected.
    
    再次查看逻辑读:
    
    
    Statistics
    ----------------------------------------------------------
    	  1  recursive calls
    	  0  db block gets
    	  8  consistent gets
    	  0  physical reads
    	  0  redo size
           2879  bytes sent via SQL*Net to client
    	396  bytes received via SQL*Net from client
    	  3  SQL*Net roundtrips to/from client
    	  0  sorts (memory)
    	  0  sorts (disk)
    	 20  rows processed
    
    
    
    select * from ( select * from ( select /*+ index_desc(a idx_page)*/ a.*,rownum rn   from page
    a  where object_id >1000 and owner='SYS'  order by object_id desc ) where rownum<=20 ) where
    rn>=0
    

  • 相关阅读:
    18周个人总结
    十六周个人总结
    排球积分规则程序
    十四周软件工程总结
    本周总结
    排球积分规则
    我的计算机生涯
    排球比赛记分员
    《怎样成为一个高手》观后感
    冲刺作业
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13352156.html
Copyright © 2020-2023  润新知