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 commit;
32
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 必须是真实存在的,否则会报错。

整理自网络

时间: 2024-10-10 23:38:00

Oracle 表的访问方式(1) ---全表扫描、通过ROWID访问表的相关文章

执行计划-数据访问方式(全表扫描与4种索引的方式)

执行计划 Oracle执行计划的相关概念: Rowid:系统给oracle数据的每行附加的一个伪列,包含数据表名称,数据库id,存储数据库id以及一个流水号等信息,rowid在行的生命周期内唯一. Recursive sql:为了执行用户语句,系统附加执行的额外操作语句,譬如对数据字典的维护等. Row source(行源):oracle执行步骤过程中,由上一个操作返回的符合条件的行的集合. Predicate(谓词):where后的限制条件. Driving table(驱动表):又称为连接的

Oracle 表的访问方式(2)-----索引扫描

索引扫描(Index scan) 我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引查找(index lookup).一个rowid唯一的表示一行数据,该行对应的数据块是通过一次i/o得到的,在此情况下该次i/o只会读取一个数据库块.在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的ROWID值.索引扫描可以由2步组成: (1) 扫描索引得到对应的rowid值. (2)

表访问方式----&gt;全表扫描(Full Table Scans, FTS)

全表扫描(Full Table Scans, FTS) 全表扫描是指Oracle在访问目标表里的数据时,会从该表所占用的第一个区(EXTENT)的第一个块(BLOCK)开始扫描,一直扫描到该表的高水位线(HWM,High Water Mark),Oracle会对这期间读到的所有数据施加目标SQL的where条件中指定的过滤条件,最后只返回那些满足过滤条件的数据. 不是说全表扫描不好,事实上Oracle在做全表扫描操作时会使用多块读,ORACLE采用一次读入多个数据块 (database bloc

Oracle性能分析6:数据访问方式之索引扫描

这节将介绍各种索引扫描方式,在了解了各种索引扫描方式的特点后,你就可以判断你的执行计划中使用的扫描方式是否正确,并可以针对获取的信息作出改进. 索引唯一扫描 在下面的场景中使用相等条件时,数据库使用索引唯一扫描. 1)查询条件中包含唯一索引中的所有列时: 2)查询条件使用主键约束列时. 下面是一个实际的例子,在表historyalarm中创建如下唯一索引: create unique index idx_historyalarm$queryid on historyalarm(queryid)

Oracle性能分析4:数据访问方法之全扫描

SQL语句执行时,Oracle的优化器会根据统计信息确定表的访问方式,一般来说,有两种基本的数据访问方式:1)全扫描.在全扫描(全表扫描或者快速全索引扫描)中,多个块被读入到一个IO运算中.2)索引扫描.索引扫描首先扫描索引叶子块以取得特定的行id(rowid),然后利用这些行id来访问父表取得实际的行数据,访问通过单块读取来完成.这里主要讲解全扫描方式,后面将介绍索引扫描. 使用全扫描 当对一个表进行全扫描时,会将表中所有数据块(block)取出并进行处理,筛选出符合条件的数据.注意Oracl

使用exchange方式切换普通表到分区表

随着数据库数据量的不断增长,有些表需要由普通的堆表转换为分区表的模式.有几种不同的方法来对此进行操作,诸如导出表数据,然后创建分区表再导入数据到分区表:使用EXCHANGE PARTITION方式来转换为分区表以及使用DBMS_REDEFINITION来在线重定义分区表.本文描述的是使用EXCHANGE PARTITION方式来实现,下面是具体的操作示例. 有关具体的dbms_redefinition在线重定义表的原理及步骤可参考:基于 dbms_redefinition 在线重定义表     

如何导致全表扫描原因

转一位大神的笔记. 导致表的执行计划做全表扫描的原因: u       SQL谓词列没有建相应的索引 u       谓词列建有相应的索引,但执行计划没有使用 Oracle不使用b*tree索引的情况大致如下 1:where条件中和null比较可能导致不使用索引 2:count,sum,ave,max,min等聚集操作时可能导致不使用索引 3:显示或者隐式的函数转换导致不使用索引 4:在cbo模式下,统计信息过于陈旧导致不使用索引 5:组合索引中没有使用前导列导致没有使用索引 6:访问的数据量超

全表 or 索引

这一篇文章证实了以前对MySQL优化程序的工作原理. MySQL就像一个人一样,总是聪明的去选择当前最快的方式去查询,而不是像Oracle数据那样死板地根据规格去查询. 查询的要求在于快.而对于数据库来说,最耗时的在磁盘IO,如何减少磁盘IO的次数,成为提高查询速度的最为关键的因素.于是在这种情况,基于B树,B+树的索引就应运而生了. 索引又有聚簇索引与非聚簇索引之分,其主要区别在于,聚簇索引非叶结点只存储主键,不存储数据行,如此以来,非叶结点占用的空间小,一个磁盘块便可以装更多的结点,这样索引

造成MySQL全表扫描的原因

全表扫描是数据库搜寻表的每一条记录的过程,直到所有符合给定条件的记录返回为止.通常在数据库中,对无索引的表进行查询一般称为全表扫描:然而有时候我们即便添加了索引,但当我们的SQL语句写的不合理的时候也会造成全表扫描.以下是经常会造成全表扫描的SQL语句及应对措施: 1. 使用null做为判断条件 如:select account from member where nickname = null; 建议在设计字段时尽量将字段的默认值设为0,改为select account where nickn