第八章 ORACLE 索引 INDEXES (一)

ORACLE DBA INDEXES

日月明王ORACLE DBA空间 http://sunmoonking.spaces.live.com

B*Tree Indexes
       在平衡 B*TREE index 的所有 leaf block 都在同一级别,这 LEVEL 代表着 IDNEX 的高度。也就是从 ROOT 查找到 LEAF BLOCK 都要访问相同数量的 BLOCK ,在百万级别的数据上一般 B*TREE 索引会是 2 3LEVEL
SQL> SQL> select index_name||' '||blevel||' '||num_rows
  2  from dba_indexes where table_name='TM_VEHICLE'
  3  /
INDEX_NAME||''||BLEVEL||''||NUM_ROWS
-----------------------------------------------------------------
TM_VEHICLE_LEAVING_DATE 2 3461864
这里 BLEVEL 不包括 LEAF ,也就是说仅代表 BRANCH B
  1* analyze index sbpopt.TM_VEHICLE_LEAVING_DATE validate structure
SQL> /
Index analyzed.
SQL> select height||' '||name from index_stats;
HEIGHT||''||NAME
------------------------------------------------------------------------------
3 TM_VEHICLE_LEAVING_DATE
这里的 HEIGHT 代表整个 INDEX TREE 的高度,包括 LEAF NODE 。(参考 cost of dual
       http://sunmoonking.spaces.live.com/blog/cns!E3BD9CBED01777CA!234.entry
Compression
COMPRESS 可能能将 INDEX TREE 的高度降低,比如从 3 降到 2 ,但是, ORACLE 将花更多的时间在寻址上, 优点是 BUFFER 中可以放更多的 INDEX ENTRIES ,可以提高 cache-hit 的命中率,物理 I/O 也会随之降低。也就是说 compress index 在提高 I/O 的同时会消耗更多 CPU
Reverse
       REVERSE KEY INDEX 能减少 leaf block 的争用,尤其是在 RAC 环境中,可以减少访问相同块的几率,同时也就能减少在 RAC instance 之间传输的 BLOCK 的数量。
Descending
SQL> create table colocated ( x int, y varchar2(80) );
表已创建。
  1  begin
  2   for i in 1 .. 100000
  3   loop
  4   insert into colocated(x,y)
  5   values (i, rpad(dbms_random.random,75,'*') );
  6   end loop;
  7*  end;
  8  /
PL/SQL 过程已成功完成。
SQL> alter table colocated add constraint colocated_pk primary key(x);
表已更改。
SQL> begin
  2  dbms_stats.gather_table_stats( user, 'COLOCATED', cascade=>true );
  3  end;
  4  /
因为 BLOCK SIZE 8K ,所以,差不多 100 行每块。
SQL> select table_name,blocks from user_tables
  2  where table_name='COLOCATED'
  3  /
TABLE_NAME                         BLOCKS
------------------------------ ----------
COLOCATED                            1252
再来看看 INDEX 是如何应用的
Set autotrace traceonly
SQL> select x,y from colocated where x<2000
  2  /
已选择 1999 行。
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=30 Card=1999 Bytes=1
          59920)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'COLOCATED' (Cost=30 Card
          =1999 Bytes=159920)
   2    1     INDEX (RANGE SCAN) OF 'COLOCATED_PK' (UNIQUE) (Cost=6 Ca
          rd=1999)
看到 INDEX (RANGE SCAN) 后面跟着一个 TABLE ACCESS (BY INDEX ROWID) ORACLE 先读 INDEX ,然后根据 INDEX ENTIRES database block 然后得到 row data 。这种读法,在数据量小的时候比较有效( thin 1%-3% fat 1%-20%
  1* select count(*) from colocated where x<2000
SQL> /
 
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=1 Bytes=5)
   1    0   SORT (AGGREGATE)
   2    1     INDEX (RANGE SCAN) OF 'COLOCATED_PK' (UNIQUE) (Cost=6 Ca
          rd=1999 Bytes=9995)
这种读法不需要读 DATA BLOCK ,仅仅读 INDEX
通过 index 去访问表,我们会发生很多 scattered ,random I/O, 意思是 index 会告诉我们都 block1,block200,block1,block352,block1 。。。而不会去顺序读,也就是我们可能多次读一个 block 。所以 2000 TABLE ACCESS BY ROWID 可能会导致 2000 table blocks 读。而这 2000 行数据可能仅仅保存在 20 BLOCK 里(这也就是为什么前面说( thin 1%-3% fat 1%-20% )的原因, % BLOCK 所能容纳的 ROWS 数有关 ,本例中 100row/block ,那如果 2row/block 呢?
CLUSTERING_FACTOR USER_INDEXES 中的 CLUSTERING_FACTOR 表示表中数据的 ORDER INDEX ORDER 的匹配程度。
       如果 clustering_factor 的值和表中的块数目大致一样,那么你的表和索引的顺序是一样的,也就是说一个 leaf block index entries 几乎指向相同 data block 。不过,如果 clustering_factor 的值接近表中的行数目,那就表明表格中的行和索引的顺序是很随机的。
select a.index_name,
  b.num_rows,
  b.blocks,
  a.clustering_factor
  from user_indexes a, user_tables b
  where index_name in ('COLOCATED_PK')
  and a.table_name = b.table_name
INDEX_NAME                                                     NUM_ROWS
------------------------------------------------------------ ----------
    BLOCKS CLUSTERING_FACTOR
---------- -----------------
COLOCATED_PK                                                     100000
      1252              1190
       可以看到 CLUSTERING_FACTOR BLOCKS 很接近,而和 num_rows 相差很大。我们如果通过 INDEX 读数据从头读到尾,会发生 1190 I/O ,因为 NEXT VAL CURR VAL 在同一个 BLOCK 上的几率很大。相反,如果 CLUSTERING_FACTOR NUM_ROWS 接近,则会释放本 BLOCK 而通过 I/O 获得其他的 BLOCK
         另外建一个按 colocated Y 排序的表 disorganized ,来排乱 index 的顺序。
SQL> create table disorganized as
  2  select x,y from colocated order by y;
Table created.
 
SQL> alter table disorganized
  2  add constraint disorganized_pk
  3  primary key (x);
Table altered.
 
SQL> begin
  2  dbms_stats.gather_table_stats( user, 'DISORGANIZED', cascade=>true );
  3  end;
  4  /
 
PL/SQL procedure successfully completed.
  1  select a.index_name,
  2    b.num_rows,
  3    b.blocks,
  4    a.clustering_factor
  5    from user_indexes a, user_tables b
  6    where index_name in ('COLOCATED_PK','DISORGANIZED_PK')
  7*   and a.table_name = b.table_name
SQL> /
INDEX_NAME                                                     NUM_ROWS
------------------------------------------------------------ ----------
    BLOCKS CLUSTERING_FACTOR
---------- -----------------
COLOCATED_PK                                                     100000
      1252              1190
DISORGANIZED_PK                                                  100094
      1219             99905
大家也可以 SQL TRACE 下, disorganized CPU LOGICAL I/O 都会比 COLOCATED 大很多,可以看到 'DISORGANIZED_PK CLUSTERING_FACTOR NUM_ROWS 很接近。我们如果通过 INDEX 读数据从头读到尾,会发生 99905 I/O ,比 COLOCATED_PK 大很多。
       相同的表相同的 INDEX 如果 CLUSTERING_FACTOR 不同执行计划也会不同,甚至相差很大。
SQL> select * from colocated where x between 10000 and 20000;
10001 rows selected.
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=142 Card=10005 Byt
          es=800400)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'COLOCATED' (TABLE) (Cost
          =142 Card=10005 Bytes=800400)
   2    1     INDEX (RANGE SCAN) OF 'COLOCATED_PK' (INDEX (UNIQUE)) (C
          ost=22 Card=10005)
SQL> select * from DISORGANIZED where x between 10000 and 20000;
10001 rows selected.
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=271 Card=10013 Byt
          es=801040)
   1    0   TABLE ACCESS (FULL) OF 'DISORGANIZED' (TABLE) (Cost=271 Ca
          rd=10013 Bytes=801040)
Bitmap Indexes
       Bitmap 7.3 版本推出的一种 INDEX Standard Edition. 不支持, Enterprise and Personal Editions 支持,是为 data warehous 设计, OLTP 不适合。一个 index key entry 可以指向多行数据,而 B*TREE 则是一对一的。 Bitmap index 存储 null entries 。适合 low distinct cardinality.
Bitmap Join Indexes
         这是 oracle9 i 推出的新的 bitmap index 类型。
create bitmap index emp_bm_idx
2 on emp( d.dname )
3 from emp e, dept d
4 where e.deptno = d.deptno
         应用时
select emp.*
2 from emp, dept
3 where emp.deptno = dept.deptno 4 and dept.dname = 'SALES'
 

你可能感兴趣的:(oracle,sql,user,tree,table,Access)