聚簇表簡介

小小黃-812發表於2014-05-22
聚簇原理:
聚簇是指:如果一組表有一些共同的列,則將這樣一組表儲存在相同的資料庫塊中;聚簇還表示把相關的資料儲存在同一個塊上。利用聚簇,
一個塊可能包含多個表的資料。概念上就是如果兩個或多個表經常做連結操作,那麼可以把需要的資料預先儲存在一起。聚簇還可以用於單個表,
可以按某個列將資料分組儲存。
更加簡單的說,比如說,EMP表和DEPT表,這兩個表儲存在不同的segment中,甚至有可能儲存在不同的TABLESPACE中,因此,他們的資料一定不會
在同一個BLOCK裡。而我們有會經常對這兩個表做關聯查詢,比如說:select * from emp,dept where emp.deptno = dept.deptno .仔細想想,查詢
主要是對BLOCK的操作,查詢的BLOCK越多,系統IO就消耗越大。如果我把這兩個表的資料聚集在少量的BLOCK裡,查詢效率一定會提高不少。
  比如我現在將值deptno=10的所有員工抽取出來,並且把對應的部門資訊也儲存在這個BLOCK裡(如果存不下了,可以為原來的塊串聯另外的塊)。
這就是索引聚簇表的工作原理。

聚簇的具體使用:
--建立聚簇
create cluster emp_dept_cluster ( deptno number(2) )size 1024;
--建立聚簇索引
create index emp_dept_cluster_idx on cluster emp_dept_cluster;
--建立聚簇索引表(dept)
create table dept
( deptno number(2) primary key, dname varchar2(14),loc varchar2(13)) cluster emp_dept_cluster(deptno);
--建立聚簇索引表(emp)
create table emp
( empno number primary key,ename varchar2(10),job varchar2(9),mgr number,hiredate date,sal number,comm number,
deptno number(2) constraint emp_fk references dept(deptno)) cluster emp_dept_cluster(deptno);
--檢視建立的聚簇索引表
select cluster_name, table_name from user_tables where cluster_name is not null order by 1;

--載入資料前必須先建立聚簇索引,否則會提示“ORA-02032:聚簇表無法在簇索引建立之前使用”
begin
for x in (select * from dept) loop
insert into dept values (x.deptno, x.dname, x.loc);
insert into emp
select * from emp where deptno = x.deptno;
end loop;
end;

--取消外來鍵
alter table emp disable constraint emp_fk;
--截斷簇(在截斷簇之前必須先關閉外來鍵引用,否則提示“ORA-02266:表中的唯一/主鍵被啟用的外來鍵引用”)
truncate cluster emp_dept_cluster;
--啟用外來鍵
alter table emp enable constraint emp_fk;
/*增加一個很大的列char(1000),加這個列是為了讓EMP行遠遠大於現在的大小。使得一個1024的聚簇無法儲存一行記錄。不能加 varchar2(1000),
因為ORACLE對varchar2儲存的原則是能省就省,如果資料資料不到1000,不會分配1000的空間。 char則是分配多少用多少*/
alter table emp add data char(1000);

--第一種方式插入資料
insert into dept select * from lttfm.dept;
insert into emp select emp.*,'*'from lttfm.emp;
--有兩條記錄兩個表的塊不同
select dept_blk,
emp_blk,
case
when dept_blk <> emp_blk then
'*'
end flag,--如果兩個表的塊不同則用*表示
deptno
from (select dbms_rowid.rowid_block_number(dept.rowid) dept_blk,
dbms_rowid.rowid_block_number(emp.rowid) emp_blk,
dept.deptno
from emp, dept
where emp.deptno = dept.deptno)
order by deptno;

--第二種方式插入資料
begin
for x in (select * from lttfm.dept) loop
insert into dept values (x.deptno, x.dname, x.loc);
insert into emp
select emp.*, 'x' from lttfm.emp where deptno = x.deptno;
end loop;
end;
--再次檢視(兩個表的塊基本相同)
select dept_blk,
emp_blk,
case
when dept_blk <> emp_blk then
'*'
end flag,
deptno
from (select dbms_rowid.rowid_block_number(dept.rowid) dept_blk,
dbms_rowid.rowid_block_number(emp.rowid) emp_blk,
dept.deptno
from emp, dept
where emp.deptno = dept.deptno)
order by deptno;
注:插入資料之前先做截斷簇

總結:
當我們通過第一種方法時,有一個問題,由於dept表的行在聚簇中佔用空間很小,但是剩餘的空間確不能存一條dept的資料(應為我們新增了
char(1000)了)。這樣就會在那些聚簇 鍵塊上導致過度的串鏈。Oracle會把包含這些資訊的一組塊串鏈或連結起來。但是如第二種方法一樣,如果同時
載入對應一個給定聚簇鍵的所有資料,就能儘可能緊地塞滿塊,等空間用完時再開始一個新塊。

什麼時候不應該使用聚簇?
1) 如果預料到聚簇中的表會大量修改:必須知道,索引聚簇會對DML的效能產生某種負面影響(特別是INSERT語句)。管理聚簇中的資料需要做更多的
工作。
2) 如果需要對聚簇中的表執行全表掃描:不只是必須對你的表中的資料執行全面掃描,還必須對(可能的)多個表中的資料進行全面掃描。由於需要
掃描更多的資料,所以全表掃描耗時更久。
3) 如果你認為需要頻繁地TRUNCATE和載入表:聚簇中的表不能截除。這是顯然的,因為聚簇在一個塊上儲存了多個表,必須刪除聚簇表中的行。
因此,如果資料主要用於讀(這並不表示“從來不寫”;聚簇表完全可以修改),而且要通過索引來讀(可以是聚簇鍵索引,也可以是聚簇表上的其他索引)
,另外會頻繁地把這些資訊聯結在一起,此時聚簇就很適合。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29144194/viewspace-1167286/,如需轉載,請註明出處,否則將追究法律責任。

相關文章