在split partition时,如果所有索引都是local index并且新split出来的partition为空时,oracle不需要rebuild index,这就是fast split。
但是当新的partition非空时,则index处于unusable状态,需要rebuild index。而在rebuild index这段时间内,如果有SQL进来,就会出问题了。
oracle并没有给出一个安全的split partition的方法,比方说如果不能做fast split则不要做split。而unusable index对于7*24系统是非常危险的。
当然你可以在split的时候去跟踪,一旦发现写入新的segment,则取消操作,但是这样还是有风险。而且一般都是定期做split,通过脚本实现,不太可能每次都手工做。
要实现fast split关键是找到正确的split point。一般我们首先跑一个查询,找出当前这个partition的最大partition key,然后再加一就是split point,然后根据这个split point来做split。但是这中间有一个时间间隔,如果这中间有新的数据插入的话,split point就不对了。
对于partition key为一个列的分区表来说,查询可以走index range(max) scan,这个时间间隔很短,可能遇到该问题的概率很小,但是如果partition key为多列的话,只能走fast full index scan,这个时间间隔可能很长,风险大大增加了。
为了避免这一风险,我采用了下面的方法:
1. 查询将要做split的partition的最大partition_key
select $sql_hint max(Partition_key+1) SPLITPOINT from $tablename partition(${maxpartname})
2. 以exclusive模式lock partition
lock table $tablename partition(${maxpartname}) in EXCLUSIVE mode
3. 再次查询要做split的partition的最大partition_key
select $sql_hint max(Partition_key+1) SPLITPOINT from $tablename partition(${maxpartname})
4. 如果step1和step3得到的结果相同,则跳到step6,不同则跳到step5
5. 提交transaction,释放lock,等待30分钟后跳到step1
6. 查看v$lock表看自己有没有block别人,如果有,跳到step5,如果没有跳到step7
7. split the partition, 如果成功,退出程序,如果失败,跳转到step5
通过上面的方法就可以保证中间没有其他的transaction去做DML。
除了保证安全外,当失败时,该程序可以sleep一段时间后重试。