发表于: 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来确定了。
最后想说的是,上面尝试用二叉树的方式解释分区的增加还是比较合适的,其实如果加上几副图的话,可能更容易把问题描述清楚。不过本文的实际意义并不大,在实际使用中没有什么的必要去了解新增分区数据来自哪个分区。所以,我也就不花力气再去配图了,有兴趣的可以自己在脑子中想象一下。