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