理解B树索引

问题描述:理解B树索引

解决方案:
有一张表:
create table cust(cust_id number,first_name varchar2(10),last_name varchar2(20));
由于经常使用last_name进行查询,在last_name上有一个索引
create index idx_cust_lname on cust(last_name);
加载数据
insert into cust values(1,'ACER','SCOTT');
insert into cust values(2,'STARK','JIM');
...
insert into cust values(10,'KHAN','BRAD');
加载完数据收集统计信息
exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'CUST',cascade=>true);

对于插入表的每一行记录,oracle都会在索引条目中存储rowid和列值(last_name),如下图:

两条虚线描述了rowid与表中列物理位置的关系
从表及索引中查询数据时,有三种可能的情况:
1、只需访问索引就可得到全部数据,不需要根据rowid访问表
2、访问索引,并通过rowid访问表
3、只访问表

场景1:所有的数据都在索引中
a、索引范围扫描:当优化器需要通过索引获取数据时,执行索引范围扫描
b、索引快速全扫描:当需要访问索引大多数数据行时,执行快速全扫描,索引结构较小,这通常会出现在计数查询中

a、索引范围扫描
select last_name from cust where last_name='ACER';
-----------------------------------------------------------------------------------
| Id  | Operation        | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                |     1 |    12 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_CUST_LNAME |     1 |    12 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          1  consistent gets
          0  physical reads
          0  redo size
        338  bytes sent via SQL*Net to client
        509  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed
对于这个查询,oracle通过索引需要访问1个数据块,因为索引高度为1


b、索引快速全扫描
select count(last_name) from cust;
-----------------------------------------------------------------------------------
| Id  | Operation        | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                |     1 |     5 |     1   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE  |                |     1 |     5 |            |          |
|   2 |   INDEX FULL SCAN| IDX_CUST_LNAME |     3 |    15 |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------


场景2:并不是所有数据都在表中
select first_name,last_name from cust where last_name='ACER';
----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |     1 |    11 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| CUST           |     1 |    11 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_CUST_LNAME |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------


场景3:仅访问表
select * from cust;
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     3 |    39 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| CUST |     3 |    39 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------


工作原理:
估算创建一个索引所需空间:
可使用dbms_space.create_index_cost进行估算
set serveroutput on
exec dbms_stats.gather_table_stats(user,'CUST');
variable used_bytes number
variable alloc_bytes number
exec dbms_space.create_index_cost('create index IDX_CUST_LNAME on cust(last_name)',:used_bytes,:alloc_bytes);
print :used_bytes
print :alloc_bytes
使用空间和分配空间

你可能感兴趣的:(oracle,oracle,11g性能优化攻略笔记)