我们有一个相当宽的表BaseData,其中包含约3,300万行。然后,我们有一个更新查询,该查询将其连接到包含各种参数的其他几个表中,应用了某些功能,按原始ID进行分组,然后将结果写到几列中的BaseData表中。
这个过程非常缓慢,因此我正在研究加快速度的方法。我在SQLServer方面拥有丰富的经验,因此我还不了解所有此类Oracle内部结构。
我怀疑的一件事是,在更新过程中,Oracle创建了每一行的版本,因此任何其他读者都可以读取该行。但是,这占用了大量资源。有什么方法可以让更新对表进行写锁定,从而不会创建每一行的版本?
你们还有其他大更新提示吗?我们已经将其分为几批。每个批次都在表的单独分区中,然后并行运行多个更新。但是仍然太慢了。
最佳答案
简短的答案是,在Oracle中,不对表采取排他锁不会阻止其他会话读取该表,也不会导致生成数据的读取一致视图的工作。同样,在Oracle中,您不能告诉会话启用“脏读”。
好吧,第一个问题是慢什么-是连接和应用函数的全部工作,还是写回去?与您的更新语句相比,SELECT my_updated_resultset FROM BASEDATA JOIN...
的性能如何?您是否已验证BaseData的读者和更新过程之间存在争执?另外,这对于企业来说太慢了,还是比您认为的慢了一点?
要考虑的另一种选择是使用分区交换来执行更新。高层次的概念是:
CREATE TABLE BASEDATA_XCHG as SELECT * FROM BASEDATA WHERE 1 = 0;
INSERT /*+ append */ INTO BASEDATA_XCHG SELECT my_updated_resultset FROM BASEDATA PARTITION (ONLY_ONE_PARTITION) JOIN...
ALTER TABLE BASEDATA EXCHANGE PARTITION (ONLY_ONE_PARTITION) WITH BASEDATA_XCHG
如果要更新BASEDATA表分区中的大多数行,请不要更新它们-创建一个新表并交换出来。蒂姆·戈曼(Tim Gorman)撰写了一篇出色的论文"Scaling to Infinity",它更深入地介绍了这一概念。您不妨检查一下。