暂无图片
oracle普通表转分区表之后的唯一索引创建问题
我来答
分享
神武天尊
2022-03-07
oracle普通表转分区表之后的唯一索引创建问题
暂无图片 10M

oracle普通表转分区表之后的唯一索引创建问题

问题描述:

普通表cz_orderlist中有ORDERID, SPID,SUBTIME等字段,其中ORDERID, SPID构成组合式唯一索引 转为新分区表,使用SUBTIME按月分区。在对新分区表创建唯一索引时遇到问题: SQL> create unique index uk_cz_orderlist on CZ_ORDERLIST(ORDERID, SPID) local; create unique index uk_cz_orderlist on CZ_ORDERLIST(ORDERID, SPID) local * ERROR at line 1: ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE index 意思是如果创建本地唯一索引,则必须把分区列包含进去。 如果我按以下方式,能够正常创建: create unique index uk_cz_orderlist on CZ_ORDERLIST(ORDERID, SPID, SUBTIME) local;

有人会问,你为什么要创建本地索引,而不是全局索引呢?

因为我之所以把这张表转为分区表,就是需要定期删除历史数据,减少数据量以提高sql处理速度。这张表数据量非常大,且每分钟都有大量的相关DML操作。

而如果我使用全局索引,则在对历史分区进行truncate或drop时出现全局索引直接失效的问题。一旦此索引失效,则会对大多数条件中使用此索引的查询造成重大影响,大量锁等待,业务无法进行。

如果我按照上面的方法,把分区键SUBTIME加进去创建的唯一索引,这又不符合业务逻辑了!

为什么呢?因为之所以原表中有这个唯一索引,就是为了防止数据重复写入,但加了SUBTIME后已经不能实现这个功能了。原因是SUBTIME是按数据写入数据库时的sysdate获取的值,此时如果前后有两条相同的数据要写入到分区表的同一个分区之中,虽然ORDERID+SPID重复了(代表重复数据),但由于sysdate不一样,系统并不会报冲突,导致数据写入成功。这就与原来的应用逻辑有偏差,导致最终数据不一致。

说了这么多,我想问问大家,有什么办法解决这个问题吗?

(注:关于在truncate或drop时加rebuild online参数在线重建索引这种方案,实测不可行。因为数据量太大,重建索引也要耗费很长时间,同样会导致大量锁等待,业务无法进行)

我来答
添加附件
收藏
分享
问题补充
4条回答
默认
最新
cqiwen
2022-03-16

在12C之前的版本,对分区表进行删除分区或者TRUNCATE分区,合并或者分裂分区,MOVE分区等DDL操作时,分区表上的全局索引会失效,通常要加上UPDATE GLOBAL INDEXES或者ONLINE关键字,可是加上这些关键字之后,本来很快的DDL操作可能就要花费很长的时间,而且还要面临锁的问题。

Oracle 12C推出了分区表全局索引异步维护特性,这个特性有效的解决了这个问题,在对分区表进行上述DDL操作时,既能快速完成操作,也能保证全局索引有效,然后通过调度JOB在固定的时候对全局索引进行维护。

其实在这个新特性实现之前,我们对分区表进行DDL操作,通常也是会选择一个业务相对比较空闲的时间来做,通常是后半夜加班来弄,有了这个新特性,就可以在白天选择一个业务相对空闲的时间来做,然后在夜间业务比较空闲的时候,让ORACLE通过JOB统一来维护全局索引。


结论:12C以前的版本选择在夜间业务比较空闲的时候进行分区的drop或truncate操作,或者将数据库升级为12C,其新特性解决了这个问题。

暂无图片 评论
暂无图片 有用 0
打赏 0
暂无图片
Lucifer三思而后行
暂无图片
2022-03-07

而如果我使用全局索引,则在对历史分区进行truncate或drop时出现全局索引直接失效的问题。一旦此索引失效,则会对大多数条件中使用此索引的查询造成重大影响,大量锁等待,业务无法进行。


关于上面的这个问题不可避免,唯一索引只能创建为全局索引,不过可以在操作时加上 update index 来避免问题,就是速度比较慢。

暂无图片 评论
暂无图片 有用 0
打赏 0
神武天尊
题主
2022-03-09
表很大,用在线重建索引的方式也解决不了这个问题。大佬还有其它解决方案没?
吾喾
2022-03-07

尝试在字段ORDERID和SPID上面选其一改为二级hash分区,这样创建唯一索引就不会报错了,但是不能保证全局唯一

暂无图片 评论
暂无图片 有用 0
打赏 0
神武天尊
题主
2022-03-09
这种方法不行。还是会报错,提示必须包含主要的分区键,而不是二级分区键。
吾喾
答主
2022-03-09
俩字段创建一个主键就能保证唯一了 alter table CZ_ORDERLIST add constraint PK_CZ_ORDERLIST primary key (ORDERID, SPID) using INDEX;
ycc
2022-03-08

这个的确是个难解,但又有业务场景的问题,个人认为完全依赖分区还是解决不了,两种思路:

1、数据库层用分区,解决清理问题,但唯一索引不建,推到应用层去保障与解决; 

2、利用分区的方式来分表,同时满足清理与唯一,但这个应用架构也得调,可能还很复杂; ^_^

暂无图片 评论
暂无图片 有用 0
打赏 0
神武天尊
题主
2022-03-09
目前我们这边有用第2种方式,虽然会产生较多的归档日志,但总比直接影响业务好。但我实际上也想知道,难道oracle搞个分区表,就没有想到我这种场景的解决方案吗?
ycc
答主
2022-03-10
不是没有想到,而是技术实现上有冲突,做不到两全吧
回答交流
提交
问题信息
请登录之后查看
邀请回答
暂无人订阅该标签,敬请期待~~
暂无图片墨值悬赏