zoukankan      html  css  js  c++  java
  • 执行计划-数据访问方式(全表扫描与4种索引的方式)

    执行计划


    Oracle执行计划的相关概念:

    Rowid:系统给oracle数据的每行附加的一个伪列,包含数据表名称,数据库id,存储数据库id以及一个流水号等信息,rowid在行的生命周期内唯一。

    Recursive sql:为了执行用户语句,系统附加执行的额外操作语句,譬如对数据字典的维护等。

    Row source(行源):oracle执行步骤过程中,由上一个操作返回的符合条件的行的集合。

    Predicate(谓词):where后的限制条件。

    Driving table(驱动表):又称为连接的外层表,主要用于嵌套与hash连接中。一般来说是将应用限制条件后,返回较少行源的表作为驱动表。在后面的描述中,将driving table称为连接操作的row source 1。

    Probed table(被探查表):连接的内层表,在我们从driving table得到具体的一行数据后,在probed table中寻找符合条件的行,所以该表应该为较大的row source,并且对应连接条件的列上应该有索引。在后面的描述中,一般将该表称为连接操作的row source 2.

    Concatenated index(组合索引):一个索引如果由多列构成,那么就称为组合索引,组合索引的第一列为引导列,只有谓词中包含引导列时,索引才可用。

    可选择性:表中某列的不同数值数量/表的总行数如果接近于1,则列的可选择性为高。

    ————————————————————————————————————————


    Oracle访问数据的存取方法:

    1. Full table scans, FTS(全表扫描):

    通过设置db_block_multiblock_read_count可以设置一次IO能读取的数据块个数,从而有效减少全表扫描时的IO总次数,也就是通过预读机制将将要访问的数据块预先读入内存中。只有在全表扫描情况下才能使用多块读操作。


    2. Table access by rowed(通过rowid存取表,rowid lookup):

    由于rowid中记录了行存储的位置,所以这是oracle存取单行数据的最快方法。


    3. Index scan(索引扫描index lookup):

    在索引中,除了存储每个索引的值外,索引还存储具有此值的行对应的rowid值,索引扫描分两步1,扫描索引得到rowid;2,通过 rowid读取具体数据。每步都是单独的一次IO,所以如果数据经限制条件过滤后的总量大于原表总行数的5%-10%,则使用索引扫描效率下降很多。而如果结果数据能够全部在索引中找到,则可以避免第二步操作,从而加快检索速度。

    根据索引类型与where限制条件的不同,有4种类型的索引扫描:

    3.1 Index unique scan(索引唯一扫描):

    存在unique或者primary key的情况下,返回单个rowid数据内容。


    3.2 Index range scan(索引范围扫描):

    1,在唯一索引上使用了range操作符(>,<,<>,>=,<=,between);2,在组合索引上,只使用部分列进行查询;3,对非唯一索引上的列进行的查询。


    3.3 Index full scan(索引全扫描):

    需要查询的数据从索引中可以全部得到。

    3.4 Index fast full scan(索引快速扫描):

    与index full scan类似,但是这种方式下不对结果进行排序。

    实验:

    SQL> create table school(sid number(4),sname varchar2(400 char), check_status number(1) default 0 check( check_status in(0,1)),accountant varchar2(20 char)unique,pwd varchar2(20 char),email varchar2(30 char),photo_path varchar2(800 char),
    constraint pk_t_school primary key(sid));
    Table created.

    SQL> create sequence shool_sid_autoinc
    minvalue 1
    maxvalue 9999999999999999999999999999
    start with 1
    increment by 1
    nocache;

    SQL> create or replace trigger insert_shool_sid_autoinc
    before insert on school
    for each row
    begin
    select shool_sid_autoinc.nextval into :new.sid from dual;
    end;
    /


    SQL> create table team(sid number(4),tid number(2),tname varchar2(400 char),number_of_teams number(2),mentor varchar2(400 char),constraint pk_t_team primary key(tid),constraint fk_t_school01 foreign key(sid) references school(sid));
    Table created.

    SQL> create sequence team_tid_autoinc
    minvalue 1
    maxvalue 9999999999999999999999999999
    start with 1
    increment by 1
    nocache;

    SQL> create or replace trigger insert_team_tid_autoinc
    before insert on team
    for each row
    begin
    select team_tid_autoinc.nextval into :new.tid from dual;
    end;
    /

    -- 重复插入十三条记录(sid不一样)
    SQL> insert into school values(3,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',66666); 
    SQL> insert into school values(4,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',66666); 
    .......
    SQL> insert into school values(15,'aaaaaaaaaaaaaaaaaaaaa',0,001,001,'964955634@qq.com',66666);
    SQL> set autotrace on;

    1. Full table scans, FTS(全表扫描)

    SQL> select * from school;
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 149184061

    ----------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    ----------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 1306 | 3 (0)| 00:00:01 |
    | 1 | TABLE ACCESS FULL| SCHOOL | 1 | 1306 | 3 (0)| 00:00:01 | 
    ----------------------------------------------------------------------------

    2. Table access by rowed(通过rowid存取表,rowid lookup)

    SQL> select rowid from school;

    ROWID
    ------------------
    AAATdsAAEAAAADHAAA
    AAATdsAAEAAAADHAAB
    AAATdsAAEAAAADHAAC
    AAATdsAAEAAAADHAAD
    AAATdsAAEAAAADHAAE
    AAATdsAAEAAAADHAAF
    AAATdsAAEAAAADHAAG
    AAATdsAAEAAAADHAAH
    AAATdsAAEAAAADHAAI
    AAATdsAAEAAAADHAAJ
    AAATdsAAEAAAADHAAK
    AAATdsAAEAAAADHAAL
    AAATdsAAEAAAADHAAM

    13 rows selected.

    SQL> select * from school where rowid='AAATdsAAEAAAADHAAA';
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2354595538

    -------------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    -------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 1318 | 1 (0)| 00:00:01 |
    | 1 | TABLE ACCESS BY USER ROWID| SCHOOL | 1 | 1318 | 1 (0)| 00:00:01 | 
    -------------------------------------------------------------------------------------

    3.1 Index unique scan(索引唯一扫描)

    SQL> select * from school where sid=3;
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3749557451

    -------------------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    -------------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 1306 | 0 (0)| 00:00:01 |
    | 1 | TABLE ACCESS BY INDEX ROWID| SCHOOL | 1 | 1306 | 0 (0)| 00:00:01 |
    |* 2 | INDEX UNIQUE SCAN | PK_T_SCHOOL | 1 | | 0 (0)| 00:00:01 |
    -------------------------------------------------------------------------------------------

    3.2 Index range scan(索引范围扫描)


    SQL> select sid from school where sid<8;

    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 3257910080

    --------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| 00:00:01 |
    |* 1 | INDEX RANGE SCAN| PK_T_SCHOOL | 1 | 13 | 0 (0)| 00:00:01 |
    --------------------------------------------------------------------------------

    3.3 Index full scan(索引全扫描)

    SQL> select sid from school;

    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2759332510

    --------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    --------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 13 | 0 (0)| 00:00:01 |
    | 1 | INDEX FULL SCAN | PK_T_SCHOOL | 1 | 13 | 0 (0)| 00:00:01 |
    --------------------------------------------------------------------------------

    3.4 Index fast full scan(索引快速扫描)

    SQL> create index in_t_school_sid_sname on school(sid,sname);
    SQL> select * from school where sname='aaaaaaaaaaaaaaaaaaaaa';
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 2494086730

    -----------------------------------------------------------------------------------------------------
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    -----------------------------------------------------------------------------------------------------
    | 0 | SELECT STATEMENT | | 1 | 1306 | 2 (0)| 00:00:01 |
    | 1 | TABLE ACCESS BY INDEX ROWID| SCHOOL | 1 | 1306 | 2 (0)| 00:00:01 |
    |* 2 | INDEX SKIP SCAN | IN_T_SCHOOL_SID_SNAME | 1 | | 1 (0)| 00:00:01 |
    -----------------------------------------------------------------------------------------------------


    总结:
    当进行index full scan的时候,oracle定位到索引的root block,然后到branch block(如果有的话),
    再定位到第一个leaf block, 然后根据leaf block的双向链表顺序读取。它所读取的块都是有顺序的,也是经
    过排序的。而index fast full scan则不同,它是从段头开始,读取包含位图块,root block,所有的branch 
    block,leaf block,读取的顺序完全由物理存储位置决定,并采取多块读,数据是无序的,每次读取
    db_file_multiblock_read_count个块。这就是为什么两者的结果区别如此之大的原因。

    转自:http://www.cnblogs.com/andy6/p/6227588.html

  • 相关阅读:
    Fidder4 顶部提示 “The system proxy was changed,click to reenable fiddler capture”。
    redis 哨兵 sentinel master slave 连接建立过程
    虚拟点赞浏览功能的大数据量测试
    python基础练习题(题目 字母识词)
    python基础练习题(题目 回文数)
    python基础练习题(题目 递归求等差数列)
    python基础练习题(题目 递归输出)
    python基础练习题(题目 递归求阶乘)
    python基础练习题(题目 阶乘求和)
    python基础练习题(题目 斐波那契数列II)
  • 原文地址:https://www.cnblogs.com/Jace06/p/6828260.html
Copyright © 2011-2022 走看看