2013-08-06 下午 星期二
------------------索引的结构------------------------
1、B树索引(平衡树索引),扫描索引就是平衡树的遍历。
B树索引是传统的索引也是用的最多的索引,根据索引提供一行或者多个行的快速访问,
通常只需要很少的IO次数就能找到正确的行。
2、需要掌握的要点:
A 树的根节点、分支节点、叶子节点(叶子块)
B 树的高度、树的层次(索引的平衡树的高度<=3的,根节点的层次为0,分之节点的层次为1,
叶子节点的层次为2),max(level)+1=height
C 范围查找时的搜索方法,涉及到叶子行使用的双向链表结构。在index range scan的时候,
会搜索这个双向链表
D 索引的唯一性特征:索引的叶子行必须是唯一的。
1 如果列值是唯一的,此时叶子行不存储ROWID,索引中列值是升序排列的。
2 如果列值是不唯一的,此时叶子行存储ROWID,索引中列值是升序排列,
在列值的分组内,rowid再升序排列。
E NULL值是不会被索引的
F 叶子行=列值+rowid 如果列值是唯一的不重复的,叶子行=列值
3、创建索引的语法:
SQL> conn plsql/plsql
Connected.
SQL> create index ind_sht_nm on org_tab(org_short_name);
Index created. --rowid一定会进入索引的,不管org_short_name是否有重复
创建唯一索引
SQL> create table tt1 as select * from all_objects;
Table created.
SQL> create unique index ind_obj_id on tt1(object_id);
Index created. --这种情况rowid是不进索引的,因为unique关键字就决定了结构。
如果列值有重复,是不能强行创建unique索引。列值必须是唯一的才行。
SQL> create unique index ind_type_id on tt1(object_type);
create unique index ind_type_id on tt1(object_type)
*
ERROR at line 1:
ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found
分析索引:
SQL> exec dbms_stats.gather_index_stats(user,'ind_obj_id'); --直接分析索引
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'tt1',cascade=>true); --分析表的时候将索引一起分析
PL/SQL procedure successfully completed.
索引空间——段的形式存在
select * from user_segments where segment_name='IND_OBJ_ID';
随着表数据的增加,索引也会不断增长。
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12 --当前的索引有12个extent。随着表数据不断增减,这个索引段也不会不断的增长
--------------------------------------------------
索引是不是也存在段空间碎片的问题?
1、delete操作,同时索引segment是不是也会有大量的空闲块生成,而且HWM会不会下降。
将表的数据删除一部分
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
20
SQL> delete from tt1 where rownum<=30000;
30000 rows deleted.
SQL> commit;
Commit complete.
SQL> select count(1) from user_extents where segment_name='TT1'; --HWM不会下降的
COUNT(1)
----------
20
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12 表的HWM没有下降,索引也没有下降
delete操作是回收碎片的空间。
--------------------------------------------------
======shrink操作回收磁盘空间,索引会不会跟着维护?===========
SQL> alter table tt1 enable row movement;
Table altered.
SQL> alter table tt1 shrink space;
Table altered.
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
17
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID'; --shrink操作只能回收表的碎片,不能回收索引的空闲空间
COUNT(1)
----------
12
SQL> alter index ind_obj_id rebuild; --索引必须要用重建的方法来回收碎片空间
Index altered.
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
4
------------------------------------------------------
move操作回收碎片的时候 ,会不会同时维护索引?
SQL> insert into tt1 select * from all_objects;
41173 rows created.
SQL> commit;
Commit complete.
SQL> alter index ind_obj_id rebuild; --重建索引
Index altered.
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
20
SQL> alter table tt1 move; --进行move操作
Table altered.
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12
SQL> select count(1) from user_extents where segment_name='TT1'; --表HWM下降了,索引没有变化
COUNT(1)
----------
17
SQL> select index_name,status from user_indexes where index_name='IND_OBJ_ID';
INDEX_NAME STATUS
------------------------------ --------
IND_OBJ_ID UNUSABLE --此时索引的状态变成不可用了。
重建索引:
SQL> alter index ind_obj_id rebuild;
Index altered.
SQL> select index_name,status from user_indexes where index_name='IND_OBJ_ID';
INDEX_NAME STATUS
------------------------------ --------
IND_OBJ_ID VALID
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
4
-------------------------------------------------------------------------
如果索引是唯一的,是否也会失效? 答案:也会失效。
SQL> drop index ind_obj_id;
Index dropped.
SQL> create unique index ind_obj_id on tt1(object_id);
Index created.
SQL> truncate table tt1;
Table truncated.
SQL> insert into tt1 select * from all_objects;
41173 rows created.
SQL> commit;
Commit complete.
SQL> alter index ind_obj_id rebuild;
Index altered.
SQL> delete from tt1 where rownum<=30000;
30000 rows deleted.
SQL> commit;
Commit complete.
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
20
SQL> alter table tt1 move;
Table altered.
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
17
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
12
SQL> select index_name,status from user_indexes where index_name='IND_OBJ_ID';
INDEX_NAME STATUS
------------------------------ --------
IND_OBJ_ID UNUSABLE
SQL> alter index ind_obj_id rebuild;
Index altered.
SQL> select index_name,status from user_indexes where index_name='IND_OBJ_ID';
INDEX_NAME STATUS
------------------------------ --------
IND_OBJ_ID VALID
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
4
实验结果看出unique索引,如果move操作后也是会失效的。
2、truncate操作,会维护索引
SQL> truncate table tt1; --不仅可以维护表,还能维护索引
Table truncated.
SQL> select count(1) from user_extents where segment_name='TT1';
COUNT(1)
----------
1
SQL> select count(1) from user_extents where segment_name='IND_OBJ_ID';
COUNT(1)
----------
1