• Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表


    1.Oracle访问表的方式

      全表扫描、通过ROWID访问表、索引扫描

    2.全表扫描(Full Table Scans, FTS)

      为实现全表扫描,Oracle顺序地访问表中每条记录,并检查每一条记录是否满足WHERE语句的限制条件。ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描,而不是只读取一个数据块,这极大的减少了I/O总次数,提高了系统的吞吐量,所以利用多块读的方法可以十分高效地实现全表扫描。需要注意的是只有在全表扫描的情况下才能使用多块读操作。在这种访问模式下,每个数据块只被读一次。

      使用FTS的前提条件:在较大的表上不建议使用全表扫描,除非取出数据的比较多,超过总量的5% -- 10%,或你想使用并行查询功能时。

    全表扫描实例(TABLE ACCESS FULL)

     1 --创建表并插入数据,并进行查询。
     2 
     3 --创建数据库
     4 SQL> create table t_captain
     5   2  (
     6   3     NO int,
     7   4     NAME VARCHAR2(32),
     8   5     WORKDAY DATE
     9   6  )
    10   7  /
    11 
    12 --创建序列
    13 SQL> CREATE SEQUENCE SEQ_USERINFO_NO
    14   2  INCREMENT BY 1   --每次加1
    15   3  START WITH 1     --从1开始计数
    16   4  /
    17 
    18 Sequence created.
    19 
    20 SQL>
    21 
    22 --插入100000条数据
    23 begin
    24   for i in 1..100000 loop
    25       INSERT INTO T_CAPTAIN VALUES(SEQ_USERINFO_NO.nextval,'captain',SYSDATE);
    26   end loop;
    27 end;
    28 /
    29 
    30 
    31 commit32 
    33 ----手动收集表的统计信息
    34 SQL> exec dbms_stats.gather_table_stats('NC60','T_CAPTAIN');
    35 
    36 PL/SQL procedure successfully completed.
    37 
    38 SQL> 
    39 
    40 
    41 --查询NO=5000的结果
    42 set autotrace traceonly  --只看查询计划
    43 select * from T_CAPTAIN where no = 5000;
    44 
    45 SQL> select * from T_CAPTAIN where no = 5000;
    46 
    47 
    48 Execution Plan
    49 ----------------------------------------------------------
    50 Plan hash value: 3680104071
    51 
    52 -------------------------------------------------------------------------------
    53 | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    54 -------------------------------------------------------------------------------
    55 |   0 | SELECT STATEMENT  |           |     1 |    21 |   103   (1)| 00:00:02 |
    56 |*  1 |  TABLE ACCESS FULL| T_CAPTAIN |     1 |    21 |   103   (1)| 00:00:02 |
    57 -------------------------------------------------------------------------------
    58 
    59 Predicate Information (identified by operation id):
    60 ---------------------------------------------------
    61 
    62    1 - filter("NO"=5000)
    63 
    64 
    65 Statistics
    66 ----------------------------------------------------------
    67           1  recursive calls
    68           0  db block gets
    69         376  consistent gets
    70           0  physical reads
    71           0  redo size
    72         551  bytes sent via SQL*Net to client
    73         419  bytes received via SQL*Net from client
    74           2  SQL*Net roundtrips to/from client
    75           0  sorts (memory)
    76           0  sorts (disk)
    77           1  rows processed
    78 
    79 SQL> 

      从查询计划我们可以看到所采用的查询方式是“TABLE ACCESS FULL”。也正是因为采用全表扫描,所以consistent gets会大些

    3.通过ROWID访问表(table access by ROWID)

      ROWID指出了该行所在的数据文件、数据块以及行在该块中的位置,所以通过ROWID来存取数据可以快速定位到目标数据上,是Oracle存取单行数据的最快方法。为了通过ROWID存取表,Oracle 首先要获取被选择行的ROWID,或者从语句的WHERE子句中得到,或者通过表的一个或多个索引的索引扫描得到。Oracle然后以得到的ROWID为依据定位每个被选择的行。下面给出使用rowid访问表的实例。

    3.1.单个rowid的情形  

     1 --查看表上rowid
     2 SQL> select rowid,no,name from T_CAPTAIN where no < 10;
     3 
     4 ROWID                      NO NAME
     5 ------------------ ---------- --------------------------------
     6 AAAWOMAAGAAA//ZAAA          1 captain
     7 AAAWOMAAGAAA//ZAAB          2 captain
     8 AAAWOMAAGAAA//ZAAC          3 captain
     9 AAAWOMAAGAAA//ZAAD          4 captain
    10 AAAWOMAAGAAA//ZAAE          5 captain
    11 AAAWOMAAGAAA//ZAAF          6 captain
    12 AAAWOMAAGAAA//ZAAG          7 captain
    13 AAAWOMAAGAAA//ZAAH          8 captain
    14 AAAWOMAAGAAA//ZAAI          9 captain
    15 
    16 
    17 --根据rowid查询记录
    18 SQL> set autotrace on
    19 SQL> set line 200
    20 SQL> select rowid,no,name from T_CAPTAIN where rowid='AAAWOMAAGAAA//ZAAA';
    21 
    22 
    23 ROWID                      NO NAME
    24 ------------------ ---------- --------------------------------
    25 AAAWOMAAGAAA//ZAAA          1 captain
    26 
    27 
    28 Execution Plan
    29 ----------------------------------------------------------
    30 Plan hash value: 2487506745
    31 
    32 ----------------------------------------------------------------------------------------
    33 | Id  | Operation                  | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    34 ----------------------------------------------------------------------------------------
    35 |   0 | SELECT STATEMENT           |           |     1 |    21 |     1   (0)| 00:00:01 |
    36 |   1 |  TABLE ACCESS BY USER ROWID| T_CAPTAIN |     1 |    21 |     1   (0)| 00:00:01 |
    37 ----------------------------------------------------------------------------------------
    38 
    39 
    40 Statistics
    41 ----------------------------------------------------------
    42           0  recursive calls
    43           0  db block gets
    44           1  consistent gets
    45           0  physical reads
    46           0  redo size
    47         558  bytes sent via SQL*Net to client
    48         419  bytes received via SQL*Net from client
    49           2  SQL*Net roundtrips to/from client
    50           0  sorts (memory)
    51           0  sorts (disk)
    52           1  rows processed
    53 
    54 SQL>  

      查询计划中说明该查询是的表访问方式是”TABLE ACCESS BY USER ROWID“,也就是直接通过USER ROWID来访问,这也是为什么只需要1次consistent gets的原因。

    3.2.多个rowid的倾向

     1 SQL> select rowid,no,name from T_CAPTAIN where rowid in ('AAAWOMAAGAAA//ZAAG','AAAWOMAAGAAA//ZAAD','AAAWOMAAGAAA//ZAAI');
     2 
     3 ROWID                      NO NAME
     4 ------------------ ---------- --------------------------------
     5 AAAWOMAAGAAA//ZAAD          4 captain
     6 AAAWOMAAGAAA//ZAAG          7 captain
     7 
     8 
     9 Execution Plan
    10 ----------------------------------------------------------
    11 Plan hash value: 2350621837
    12 
    13 -----------------------------------------------------------------------------------------
    14 | Id  | Operation                   | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    15 -----------------------------------------------------------------------------------------
    16 |   0 | SELECT STATEMENT            |           |     1 |    21 |     1   (0)| 00:00:01 |
    17 |   1 |  INLIST ITERATOR            |           |       |       |            |          |
    18 |   2 |   TABLE ACCESS BY USER ROWID| T_CAPTAIN |     1 |    21 |     1   (0)| 00:00:01 |
    19 -----------------------------------------------------------------------------------------
    20 
    21 
    22 Statistics
    23 ----------------------------------------------------------
    24           1  recursive calls
    25           0  db block gets
    26           2  consistent gets
    27           0  physical reads
    28           0  redo size
    29         621  bytes sent via SQL*Net to client
    30         419  bytes received via SQL*Net from client
    31           2  SQL*Net roundtrips to/from client
    32           0  sorts (memory)
    33           0  sorts (disk)
    34           2  rows processed
    35 
    36 SQL>

    查询计划分析:

    1.上面的执行计划中出现了INLIST ITERATOR,即INLIST迭代,该操作说明其子操作多次重复时,会出现该操作。 

    2.由于我们使用了in运算,且传递了2个rowid,故出现INLIST迭代操作

    3.迭代操作意味着条件中的对象列表一个接一个的迭代传递给子操作

    4.此时统计信息中的consistent gets为2,并不是因为传入的rowid有2个,假如传入的rowid有4个,consistent gets也等于2。

    注意:使用ROWID进行查询的前提是我们明确知道了一个正确的ROWID,然后通过这个ROWID进行查询。所以这里所提到的所有ROWID 必须是真实存在的,否则会报错。

    整理自网络

  • 相关阅读:
    关于Android的布局
    一个新的开端
    Flux的基础概念和实战入门
    在Redux中使用插件createAction之后
    学习
    Object.assign() 对象的扩展
    Redux 中的CombineReducer的函数详解
    React组件的防呆机制(propTypes)
    css的新特性 calc () 使用
    shim和polyfill有什么区别
  • 原文地址:https://www.cnblogs.com/polestar/p/4131642.html
Copyright © 2020-2023  润新知