zoukankan      html  css  js  c++  java
  • 12c分页查询特性FETCH FIRST ROWS,OFFSET ROWS FETCH NEXT ROW LIMIT Clause子句

    Database 12c的FETCH FIRST ROWS特性可以简化老版本中ROW_NUM()或ROWNUM的分页排序写法, 大幅节约开发花在分页查询语句上的时间。 row-limiting子句用以限制某个查询返回的行数
    • 可以通过FETCH FIRST/NEXT关键字指定返回结果的行数
    • 可以通过PERCENT关键字指定返回结果的行数比例
    • 可以通过OFFSET关键字指定返回从结果集中的某一行之后行数
    12c row-limiting子句对于排序数据限制返回行今后会广泛使用(MySQL上早就有的特性,MySQL开发该特性可能是特别考虑到对于网站分页查询的简化),也可以被称作Top-N查询。     示意图:   SQL Row-Limiting Clause Examples 我们这里来对比老的ROWNUM写法等价的FETCH ROWS写法的实际性能对比:
    create table larget tablespace users as select rownum t1, rpad('M',99,'A') t2, rpad('M',99,'A') t3, rpad('M',99,'A') t4 from dual connect by level<=99999;
    
    SQL> create index pk_ind on larget(t1) tablespace users;
    
    Index created.
    
    select llv.* from 
    (
    select rownum rn, ll.* from
    (select /*+ index( larget pk_ind */ *  from larget where t1 is not null order by t1 ) ll
    where rownum<=20) llv 
    where 
    llv.rn>=1;
    
    20 rows selected.
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3843929721
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation                      | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT               |        |    20 |  3580 |     3   (0)| 00:00:01 |
    |*  1 |  VIEW                          |        |    20 |  3580 |     3   (0)| 00:00:01 |
    |*  2 |   COUNT STOPKEY                |        |       |       |            |          |
    |   3 |    VIEW                        |        |    20 |  3320 |     3   (0)| 00:00:01 |
    |   4 |     TABLE ACCESS BY INDEX ROWID| LARGET | 99999 |    29M|     3   (0)| 00:00:01 |
    |*  5 |      INDEX FULL SCAN           | PK_IND |    20 |       |     2   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("LLV"."RN">=1)
       2 - filter(ROWNUM<=20)
       5 - filter("T1" IS NOT NULL)
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              7  consistent gets
              0  physical reads
              0  redo size
           1841  bytes sent via SQL*Net to client
            554  bytes received via SQL*Net from client
              3  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             20  rows processed
    
    SQL> select * from larget where t1 is not null order by t1 fetch first 20 rows only;
    
    20 rows selected.
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3254405084
    
    ----------------------------------------------------------------------------------------
    | Id  | Operation                     | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |        | 99999 |    18M|  4573   (1)| 00:00:01 |
    |*  1 |  VIEW                         |        | 99999 |    18M|  4573   (1)| 00:00:01 |
    |*  2 |   WINDOW NOSORT STOPKEY       |        | 99999 |    29M|  4573   (1)| 00:00:01 |
    |   3 |    TABLE ACCESS BY INDEX ROWID| LARGET | 99999 |    29M|  4573   (1)| 00:00:01 |
    |*  4 |     INDEX FULL SCAN           | PK_IND | 99999 |       |   224   (1)| 00:00:01 |
    ----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=20)
       2 - filter(ROW_NUMBER() OVER ( ORDER BY "LARGET"."T1")<=20)
       4 - filter("T1" IS NOT NULL)
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
              7  consistent gets
              0  physical reads
              0  redo size
           1717  bytes sent via SQL*Net to client
            554  bytes received via SQL*Net from client
              3  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
             20  rows processed
    
    select llv.* from 
    (
    select rownum rn, ll.* from
    (select /*+ index( larget pk_ind */ *  from larget where t1 is not null order by t1 ) ll
    where rownum<=20000) llv 
    where 
    llv.rn>=18000;		 
    
    2001 rows selected.
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3843929721
    
    -----------------------------------------------------------------------------------------
    | Id  | Operation                      | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT               |        | 20000 |  3496K|   916   (0)| 00:00:01 |
    |*  1 |  VIEW                          |        | 20000 |  3496K|   916   (0)| 00:00:01 |
    |*  2 |   COUNT STOPKEY                |        |       |       |            |          |
    |   3 |    VIEW                        |        | 20000 |  3242K|   916   (0)| 00:00:01 |
    |   4 |     TABLE ACCESS BY INDEX ROWID| LARGET | 99999 |    29M|   916   (0)| 00:00:01 |
    |*  5 |      INDEX FULL SCAN           | PK_IND | 20000 |       |    46   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("LLV"."RN">=18000)
       2 - filter(ROWNUM<=20000)
       5 - filter("T1" IS NOT NULL)
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
           1177  consistent gets
            904  physical reads
              0  redo size
          56804  bytes sent via SQL*Net to client
           2006  bytes received via SQL*Net from client
            135  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
           2001  rows processed
    
    select * from larget where t1 is not null order by t1  OFFSET 17999 ROWS FETCH NEXT 2001 ROWS ONLY;
    
            T1
    
    ----------
    
         18001
    
    	 Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3254405084
    
    ----------------------------------------------------------------------------------------
    | Id  | Operation                     | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |        | 99999 |    18M|  4573   (1)| 00:00:01 |
    |*  1 |  VIEW                         |        | 99999 |    18M|  4573   (1)| 00:00:01 |
    |*  2 |   WINDOW NOSORT STOPKEY       |        | 99999 |    29M|  4573   (1)| 00:00:01 |
    |   3 |    TABLE ACCESS BY INDEX ROWID| LARGET | 99999 |    29M|  4573   (1)| 00:00:01 |
    |*  4 |     INDEX FULL SCAN           | PK_IND | 99999 |       |   224   (1)| 00:00:01 |
    ----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=CASE  WHEN
                  (17999>=0) THEN 17999 ELSE 0 END +2001 AND
                  "from$_subquery$_003"."rowlimit_$$_rownumber">17999)
       2 - filter(ROW_NUMBER() OVER ( ORDER BY "LARGET"."T1")<=CASE  WHEN
                  (17999>=0) THEN 17999 ELSE 0 END +2001)
       4 - filter("T1" IS NOT NULL)
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
           1177  consistent gets
              0  physical reads
              0  redo size
          46757  bytes sent via SQL*Net to client
           2006  bytes received via SQL*Net from client
            135  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
           2001  rows processed
    
    不仅可以指定fetch的rows数目,还可以指定返回的行比例,但是这一般会引起真正的INDEX FULL SCAN 
    
    SQL> select * from larget where t1 is not null order by t1 fetch first 1 percent rows only;
    
    1000 rows selected.
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 978863371
    
    ----------------------------------------------------------------------------------------
    | Id  | Operation                     | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT              |        | 99999 |    19M|  4573   (1)| 00:00:01 |
    |*  1 |  VIEW                         |        | 99999 |    19M|  4573   (1)| 00:00:01 |
    |   2 |   WINDOW BUFFER               |        | 99999 |    29M|  4573   (1)| 00:00:01 |
    |   3 |    TABLE ACCESS BY INDEX ROWID| LARGET | 99999 |    29M|  4573   (1)| 00:00:01 |
    |*  4 |     INDEX FULL SCAN           | PK_IND | 99999 |       |   224   (1)| 00:00:01 |
    ----------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=CEIL("from$_subquer
                  y$_003"."rowlimit_$$_total"*1/100))
       4 - filter("T1" IS NOT NULL)
    
    Statistics
    ----------------------------------------------------------
              1  recursive calls
              0  db block gets
           4571  consistent gets
           3656  physical reads
              0  redo size
          22863  bytes sent via SQL*Net to client
           1269  bytes received via SQL*Net from client
             68  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
           1000  rows processed
    
    SQL>
        从以上的2个演示对比,可以看到2种写法实际消耗逻辑读数目是类似的;即12c 中FETCH FIRST ROWS,OFFSET ROWS FETCH NEXT的写法在实际性能上并不比传统的rownum写法来的效率低。 但是可以看到CBO在评估fetch rows执行计划的成本时其 TABLE ACCESS BY INDEX ROWID成本要比rownum写法高出不少,这似乎是由于不同的基数计算导致的。
  • 相关阅读:
    计算器第七次作业——总结
    计算器第六次作业——界面
    链表反转
    计算器第五次作业——更新
    求圆的面积
    计算器第四次作业——实现
    计算器第三次作业——完善
    计算器第三次作业——初步
    成长函数
    单个H扩展到多个H时,机器学习的保证
  • 原文地址:https://www.cnblogs.com/macleanoracle/p/2968340.html
Copyright © 2011-2022 走看看