ORACLE 迁移到 MogDB 之存储过程改造:分区表指定切割点进行分区切割的改造
在 ORACLE 迁移到 MogDB 的过程中,遇到了指定切割点进行分区切割的问题,这里记录如下:
1 | sys@ORA19CK> CREATE TABLE test_split_tbs ( |
查看分区名和 id
1 | sys@ORA19CK> select object_name,subobject_name,object_id from dba_objects where OBJECT_NAME='TEST_SPLIT_TBS'; |
可以看到 ALARM_20500101 的 OBJECT_ID为 88710
切割分区
alter table TEST_SPLIT_TBS split partition alarm_20500101 at (to_date(‘2024-08-01’,’YYYY-MM-DD’)) into (partition alarm_20240731,partition alarm_20500101);
注意:这个切割分区是将原来的分区 alarm_20500101 切割为 alarm_20240731 和 alarm_20500101,也就是新分区还是原来的名字,相当于新增了一个分区。
1 | sys@ORA19CK>alter table TEST_SPLIT_TBS split partition alarm_20500101 at (to_date('2024-08-01','YYYY-MM-DD')) into (partition alarm_20240731,partition alarm_20500101); |
可以看到 oracle 可以切割成功。
切割分区之后再查看分区名和对象id
1 | sys@ORA19CK>select object_name,subobject_name,object_id from dba_objects where OBJECT_NAME='TEST_SPLIT_TBS'; |
可以看到切割的源分区 ALARM_20500101
的 OBJECT_ID 仍然为 88710
但是 MogDB 进行切割的时候报错如下:
创建分区表:
1 | create table test_split_tbs1( |
查看分区名称
1 | select |
1 | oid | relname | relname | parentid |
1 | liups=>alter table TEST_SPLIT_TBS split partition alarm_20500101 at (to_date('2024-08-01','YYYY-MM-DD')) into (partition alarm_20240731,partition alarm_20500101); |
MogDB 报 : ERROR: resulting partition "alarm_20500101" name conflicts with that of an existing partition
也就是新分区的名跟原来的分区重名了。
1 | AT ( partition_value ) INTO ( PARTITION partition_name [ TABLESPACE tablespacename ] , PARTITION partition_name [ TABLESPACE tablespacename ] ) |
查看官方手册:https://docs.mogdb.io/zh/mogdb/v5.0/dolphin-alter-table-partition#语法格式
这就是 指定切割点split_point_clause的。
很明显写明了:,指定切割点的方式只能把一个分区切割成两个新分区。
但是通过上面很显然 ORACLE是 没有这个限制的。
那去测试下 原生的PG 是否支持呢。
PG 版本是 16.3
1 | liups=# create table test_split_tbs( |
完蛋,PostgreSQL 竟然都不支持 oracle 创建分区表的语法,在 16.3 不支持,那我相信之前的版本也不支持。那就不测试了。经过查询
那我们知道了 MogDB 在切割分区的时候,新分区不能跟原来的分区重名,怎么解决呢。首先这是在存储过程中实现的,也就是每天从maxvaleu 中分割一个新分区出来,maxvalue 的分区名称不能变,还是原来的。
这能有几个考量:maxvalue 分区的名称是否能发生变化,有人会说了,maxvalue的分区改个名称就好了,加个数字1或者a、b、c之类的就行了,在手动单独执行的时候确实可行,但是如果在存储过程中还有结合业务来看呢,并没有这么简单。这个maxvalue 分区是 alarm_20500101 ,在存储过程中写死的,如果你切割的分区产生了变化,那下一次运行的时候,maxvalue分区名都边了,肯定下一次执行就报错了,都找不到这个 alarm_20500101了。
既然产生了变化,那就存储过程加个判断就好了,定义俩变量,取出 maxvalue 分区的名称,给变量 ,然后另一个变量再maxvalue 上加个数字,那有个问题,每次加一个字符串,多长执行之后那这个分区名就很很长了。。肯定会超过限制的,尤其一天一个分区的,再说了也不美观。还有人说:大月max 小月max1 7月 单独分开,我是没看懂,可能他这个是 按照月分区的,不过给了我一个解决方案就是判断当前日期是偶数还是奇数,如果是偶数maxvalue的分区叫max,奇数就是max1,这也是个解决方案,解决了切割分区的问题,需要加上一个判断当前日期是奇数还是偶数,那有没有一个maxvalue 分区名不变的方案呢,既然他存储过程中写死了分区的名称为 alarm_20500101,那你能确保应用了没有写这个分区名称嘛?
这里我的解决方案是什么呢,其实很简单:
就是每次切割的时候,maxvalues 都切割为 :alarm_20500101_temp,切割完成之后,再重命名。
1 | alter table TEST_SPLIT_TBS split partition alarm_20500101 at (to_date('2024-08-01','YYYY-MM-DD')) into (partition alarm_20240731,partition alarm_20500101_temp); |
也就是在切割完成之后,紧跟着一个重命名,
1 | ALTER TABLE test_split_tbs RENAME PARTITION alarm_20500101_temp TO alarm_20500101; |
这样可以顺利切换,并能保证maxvalue 的分区名不变。当然了如果您要说,在重命名需要一定的时间(零点几毫秒吧),业务并发大,影响业务怎么办,如果你有那么大的并发就另说了。
具体的存储过程中的改造的SQL 如下:
1 | v_Sql:='alter table '||v_TableName||' SPLIT partition ALARM_20500101 at (to_date('''||v_PartDateStr||''',''YYYY-MM-DD'')) INTO (PARTITION '||v_PartName||', PARTITION ALARM_20500101temp)'; |
原文作者: Hi.MogDB
原文链接: https://hi.mogdb.org/posts/65c9694d/
许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议