聊聊Oracle聚簇Cluster(上)

realkid4發表於2013-10-15

 

Oracle資料表三種基本型別:堆表Heap Table、索引組織表IOT和聚簇表Cluster。在我們日常中,最常用也是適應性最好的一種資料表就是堆表Heap Table。一般在沒有特殊效能缺陷和特性要求的情況下,堆表是我們首先的選項。

 

IOT是一種融合資料到索引結構上的資料表型別。在筆者之前的文章中,詳細介紹了IOT的結構、特性和適應場景,同時也對段溢位Segment Overflow、邏輯Rowid和Secondary Index等概念進行過闡述。

 

本篇我們介紹一下聚簇。

 

1、概說聚簇Cluster

 

應該說,三種資料表型別中,我們最不常用的結構應該是聚簇。聚簇也是和其他兩種資料表差異最大的一種結構型別,最大的區別在於:聚簇是可以單獨存在的。

 

在Oracle儲存結構中,我們必須遵循兩個概念就是物件和段Segment。我們可以建立很多物件,比如資料表、索引、檢視,但是並不是每個物件都會“真刀真槍”的佔用儲存空間。Oracle空間分配是依據邏輯表空間、段物件、分割槽和塊。只有資料表、索引等物件,才是可以真正使用空間的,分配Segment的。

 

堆表和索引組織表雖然有差別,但是本質上是類似的。堆表中,索引和資料表是分別的資料段結構,索引段和資料表段保持一致性。而IOT實現了索引和資料表段的合一。資料表的所有內容,依據主鍵順序被儲存在IOT索引樹的葉子節點上。由於資料表內容的特殊性,比如欄位過大的情況,都是透過溢位段實現。

 

而Cluster完全不同,Cluster是一種單獨的段結構,或者筆者理解為單獨的段空間容器。在沒有資料表和索引的時候,Cluster段是可以單獨存在的。依據一定的規則,如連線鍵(Join Key),可以將多個資料表資料儲存在同一個段中。並且依據一定場景實現快速檢索連線。

 

我們為什麼使用Cluster資料表。最常見的解釋是減少關聯檢索時候進行IO的數量。傳統的資料表結構,兩個表連線,至少要進行兩次資料塊的檢索。而Cluster過程,由於都是儲存在一起(注意:相同Segment)。

 

Cluster進行使用的時候,有兩個型別進行選擇,分別為B樹Cluster和雜湊Hash Cluster。兩者既有相同的結構,又有細微的差異。

 

2、實驗環境介紹

 

我們選擇Oracle 11gR2進行實驗。

 

 

SQL> select * from v$version;

 

BANNER

-----------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production

PL/SQL Release 11.2.0.3.0 - Production

CORE    11.2.0.3.0  Production

 

TNS for Linux: Version 11.2.0.3.0 - Production

NLSRTL Version 11.2.0.3.0 – Production

 

 

建立專門的使用者進行實驗。

 

 

SQL> create user test identified by test default tablespace users;

User created

 

SQL> grant resource, connect to test;

Grant succeeded

 

SQL> grant create cluster to test;

Grant succeeded

 

SQL> grant select any table to test;

Grant succeeded

 

SQL> grant select any dictionary to test;

Grant succeeded

 

 

3、B樹Cluster實驗

 

透過一系列的實驗,我們來探討發現Cluster資料表的特性和使用。Oracle Cluster不是隨任何資料表物件建立,而是可以透過SQL語句create cluster來進行建立。

 

 

SQL> create cluster emp_dept (deptno number) size 600;

Cluster created

 

SQL> select cluster_name, tablespace_name, cluster_type, key_size from user_clusters;

 

CLUSTER_NAME          TABLESPACE_NAME              CLUSTER_TYPE   KEY_SIZE

-------------------------- -------------------------- ------------ ----------

EMP_DEPT                       USERS                   INDEX               600

 

 

注意兩個問題,一個是建立cluster的過程中我們指定的size 600。這個是用於指定cluster鍵大致大小,指定之後,就可以實現空間的預留。如果這個取值設定不合理,容易引起Cluster結構的混亂。

 

另一個問題是tablespace_name,Cluster物件既然包括了tablespace資訊,就必然是佔用空間的,也必然以segment的形式出現。

 

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='EMP_DEPT';

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

CLUSTER                     1           4          522      65536          8

 

 

注意:此時我們沒有建立資料表或者索引,但是cluster segment已經存在出現。下面我們依託cluster emp_dept建立資料表。

 

 

SQL> create table emp (empno number, empname varchar2(10), deptno number) cluster emp_dept(deptno);

Table created

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='EMP_DEPT';

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

CLUSTER                     1           4          522      65536          8

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='EMP';

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

 

 

依託cluster建立資料表的時候,要指定出哪個欄位是cluster的key鍵值。從段結構資料字典中,我們不能看到資料表的段資訊,只有cluster的段資訊。從dba_tables中,我們的確看到資料表成功建立。

 

 

SQL> select segment_created from dba_tables where wner='TEST' and table_name='EMP';

SEGMENT_CREATED

---------------

YES

 

 

此時,我們嘗試往資料表emp新增資料,是被禁止的。

 

 

SQL> insert into emp select empno, ename, deptno from scott.emp;

insert into emp select empno, ename, deptno from scott.emp

 

ORA-02032: 聚簇表無法在簇索引建立之前使用

 

 

在這裡,我們意識到使用cluster還需要建立專門的cluster index。為了進行連線測試,先建立第二張資料表。

 

 

SQL> create table dept (deptno number primary key, deptname varchar2(10)) cluster emp_dept(deptno);

 

Table created

 

SQL> select segment_created from dba_tables where wner='TEST' and table_name='DEPT';

 

SEGMENT_CREATED

---------------

YES

 

 

同時,建立了需要的索引結構。

 

 

SQL> create index idx_emp_dept on cluster emp_dept;

Index created

 

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name in ('EMP_DEPT','IDX_EMP_DEPT');

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

INDEX                       1           4          538      65536          8

CLUSTER                     1           4          522      65536          8

 

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='EMP';

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='DEPT';

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

 

--Index後設資料資訊

SQL> select index_type, table_name, table_type, UNIQUENESS from dba_indexes where wner='TEST' and index_name='IDX_EMP_DEPT';

 

INDEX_TYPE                TABLE_NAME                     TABLE_TYPE  UNIQUENESS

--------------------------- ---------------------------- ----------- ----------

CLUSTER                     EMP_DEPT                       CLUSTER     UNIQUE

 

 

我們建立了兩張資料表和一個索引,只有cluster和索引成為了段物件。明顯的是兩個資料表都包括儲存在了cluster段結構中。

 

建立索引的過程和普通索引是不同的。我們沒有給資料表建索引,而是給cluster物件。從dba_indexes檢視中,可以看到差異和不同。

 

下面我們灌入資料。

 

 

SQL> insert into dept select deptno, dname from scott.dept;

4 rows inserted

 

SQL> insert into emp select empno, ename, deptno from scott.emp;

14 rows inserted

 

SQL> commit;

Commit complete

 

 

此時,段結構依然維持一個cluster和一個索引的形態。

 

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='EMP';

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name='DEPT';

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

 

SQL> select SEGMENT_TYPE, extents, HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS from dba_segments where wner='TEST' and segment_name in ('EMP_DEPT','IDX_EMP_DEPT');

 

SEGMENT_TYPE          EXTENTS HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS

------------------ ---------- ----------- ------------ ---------- ----------

CLUSTER                     1           4          522      65536          8

INDEX                       1           4          538      65536          8

 

 

使用cluster最大的好處在於連線,我們檢視一下連線情況下的執行計劃。

 

 

 

SQL> explain plan for select * from emp a, dept b where a.deptno=b.deptno;

Explained

 

SQL> select * from table(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 1709228156

-------------------------------------------------------------------------------

| Id  | Operation            | Name         | Rows  | Bytes | Cost (%CPU)| Time

-------------------------------------------------------------------------------

|   0 | SELECT STATEMENT      |             |    14 |   350 |     6   (0)| 00:0

|   1 |  NESTED LOOPS         |             |    14 |   350 |     6   (0)| 00:0

|   2 |   TABLE ACCESS FULL   | DEPT        |     4 |    48 |     3   (0)| 00:0

|   3 |   TABLE ACCESS CLUSTER| EMP         |     4 |    52 |     1   (0)| 00:0

|*  4 |    INDEX UNIQUE SCAN  | IDX_EMP_DEPT |    1 |       |     0   (0)| 00:0

-------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   4 - access("A"."DEPTNO"="B"."DEPTNO")

 

16 rows selected

 

 

cluster本質上就是一個容器,如果我們需要刪除cluster,需要將其中資料表物件全部刪除之後,方可執行。或者使用including tables子句。

 

 

SQL> drop cluster emp_dept;

drop cluster emp_dept

 

ORA-00951: 簇非空

 

SQL> drop cluster emp_dept including tables;

Cluster dropped

 

 

本部分介紹的是B樹聚簇,也是簡單的一種聚簇形式。下面我們來討論Hash Cluster的特點。

 

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

相關文章