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'