暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle HASH分区表增加新的分区的一点研究

原创 yangtingkun 2020-02-07
2898

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来确定了。

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

最后修改时间:2020-02-07 14:16:57
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论