發表於: 2006.08.18 17:58
分類: ORACLE
出處: http://yangtingkun.itpub.net/post/468/195510
---------------------------------------------------------------
Oracle的HASH分區,沒有SPLIT PARTITION語言,替代的語句是ADD PARTITION。研究了一下發現ADD PARTITION語句和RANGE、LIST分區中的SPLIT PARTITION是十分相似的。
Oracle用於HASH分區的hash函數應該是唯一確定的,也就是說,給定分區個數,那麼分區鍵值在這些分區中的分佈就是固定不變的。否則的話,Oracle的HASH分區表就無法進行分區交換操作。
Oracle推薦分區數是2的冪,這樣可以保證各個分區的數據分佈相對均勻。其實對於分區數不是2的冪的HASH分區,可以看作是2的冪的一種變形。
首先考慮分區數是2的整數冪的情況:當Oracle的分區數從2個變爲4個,Oracle並不需要將所有數據重新打亂,而是將原有的2個分區每個都一分爲二。同樣的道理,如果將分區數設置爲8,Oracle會將原有的4個分區一分爲二。
SQL> CREATE TABLE TEST_HASH2 (ID NUMBER) PARTITION BY HASH(ID)
2 (PARTITION P2_1, PARTITION P2_2);
表已創建。
SQL> CREATE TABLE TEST_HASH4 (ID NUMBER) PARTITION BY HASH(ID)
2 (PARTITION P4_1, PARTITION P4_2, PARTITION P4_3, PARTITION P4_4);
表已創建。
SQL> CREATE TABLE TEST_HASH8 (ID NUMBER) PARTITION BY HASH(ID)
2 (PARTITION P8_1, PARTITION P8_2, PARTITION P8_3, PARTITION P8_4,
3 PARTITION P8_5, PARTITION P8_6, PARTITION P8_7, PARTITION P8_8);
表已創建。
SQL> INSERT INTO TEST_HASH2 SELECT ROWNUM FROM USER_TABLES;
已創建22行。
SQL> INSERT INTO TEST_HASH4 SELECT ROWNUM FROM USER_TABLES;
已創建22行。
SQL> INSERT INTO TEST_HASH8 SELECT ROWNUM FROM USER_TABLES;
已創建22行。
SQL> COMMIT;
提交完成。
SQL> SELECT * FROM TEST_HASH2 PARTITION(P2_1);
ID
----------
2
5
6
8
11
13
18
20
21
已選擇9行。
SQL> SELECT * FROM TEST_HASH4 PARTITION(P4_1);
ID
----------
6
11
13
SQL> SELECT * FROM TEST_HASH4 PARTITION(P4_3);
ID
----------
2
5
8
18
20
21
已選擇6行。
SQL> SELECT * FROM TEST_HASH8 PARTITION(P8_1);
ID
----------
6
11
SQL> SELECT * FROM TEST_HASH8 PARTITION(P8_5);
ID
----------
13
SQL> SELECT * FROM TEST_HASH8 PARTITION(P8_3);
ID
----------
5
21
SQL> SELECT * FROM TEST_HASH8 PARTITION(P8_7);
ID
----------
2
8
18
20
舉個形象一些的例子,Oracle的HASH分區就像是一棵大的二叉樹。每個分區就相當於二叉樹的一個葉節點。二叉樹的第一層,只有一個根節點,對應只有1個分區的情況。二叉樹的第二層,兩個葉節點,對應2個分區的情況。二叉樹的第三層,4個葉節點,對應4個分區的情況。二叉樹的第n層,2^(n-1)個葉節點,對應2^(n-1)個分區情況。
每個分區中包含的分區鍵值都來自它的上層枝節點。
而對於分區數爲非2的整數冪的情況,則可以看作上面的一種變形。可以看作樹的最底層葉節點沒有完全填滿,還保留了幾個上一層的葉節點。以6個分區爲例,可以看成一個4層2叉樹,第4層包括四個葉節點,第3層包括兩個葉節點。
上面說了這麼多,主要是爲了說明,Oracle的HASH分區在增加分區時,最多隻會影響到一個分區的數據。如果分區鍵值的分佈恰好在新增分區中不存在,那麼新增分區時,不會影響任何一個已經存在的分區。否則的話,只會影響它的上一層的枝節點分區。
Oracle首先會將本層的所有葉節點填滿,然後纔會增加新的一層。
Oracle在增加新的分區時,會根據HASH函數確定原有分區內的數據在兩個新分區內的分佈,增加完分區後,屬於新分區的數據已經從源分區中轉移到新分區中。
從二叉樹的模型來說,增加分區的過程相當於一個節點分裂成兩個葉節點的情況。左節點對應着分裂前的節點,而右節點就是新增的節點。
Oracle新增分區時,將從哪個分區中分裂出數據是可以判斷出來的。Oracle增加分區和分裂數據的分區都是按照順序進行的。
如果要增加的分區是第N個分區,大於等於N的最小2的整數冪爲M,則當增加第N個分區時,這個分區的數據來源於分區N-M/2。
上面的公式過於抽象了,我們舉兩個具體的例子:
目前有4個分區,要增加第5個分區,大於等於5的最小整數冪是8,根據公式,5-8/2=1,第5個分區的數據來源於分區1。
目前有7個分區,要增加第8個分區,而大於等於8的最小整數冪也是8,根據公式,8-8/2=4,第8個分區的數據來源於分區4。
下面驗證一下:
SQL> SELECT * FROM TEST_HASH4 PARTITION (P4_1);
ID
----------
6
11
13
SQL> ALTER TABLE TEST_HASH4 ADD PARTITION P4_5;
表已更改。
SQL> SELECT * FROM TEST_HASH4 PARTITION (P4_5);
ID
----------
13
SQL> CREATE TABLE TEST_HASH7 (ID) PARTITION BY HASH(ID)
2 (PARTITION P7_1, PARTITION P7_2, PARTITION P7_3, PARTITION P7_4,
3 PARTITION P7_5, PARTITION P7_6, PARTITION P7_7)
4 AS SELECT ROWNUM FROM USER_TABLES;
表已創建。
SQL> SELECT * FROM TEST_HASH7 PARTITION (P7_4);
ID
----------
1
3
4
7
14
15
16
已選擇7行。
SQL> ALTER TABLE TEST_HASH7 ADD PARTITION P7_8;
表已更改。
SQL> SELECT * FROM TEST_HASH7 PARTITION(P7_8);
ID
----------
1
7
14
15
SQL> SELECT * FROM TEST_HASH7 PARTITION (P7_4);
ID
----------
3
4
16
分區合併操作的算法相當於增加分區的逆向操作,這裏就不在描述了。
從上面的分析可以看出,HASH分區的ADD PARTITION和RANGE分區、LIST分區的SPLIT PARTITION很類似,都是從一個分區中取出一部分數據放到新增的分區中。唯一的區別在於,SPLIT操作允許用戶指定操作的分區和SPLIT的位置,而ADD PARTITION則完全由Oracle來確定了。
最後想說的是,上面嘗試用二叉樹的方式解釋分區的增加還是比較合適的,其實如果加上幾副圖的話,可能更容易把問題描述清楚。不過本文的實際意義並不大,在實際使用中沒有什麼的必要去了解新增分區數據來自哪個分區。所以,我也就不花力氣再去配圖了,有興趣的可以自己在腦子中想象一下。