如何批量更新oracle pl / sql中的大表以避免耗尽undospace?

时间:2010-08-22 19:54:25

标签: oracle plsql

我有一张非常大的桌子(5毫米的记录)。我正在尝试使用随机字母数字对表格的VARCHAR2列进行模糊处理。我的过程在较小的数据集上成功执行,但它最终会在我无法控制的设置的远程数据库上使用,所以我想批量执行UPDATE语句以避免耗尽undospace。

我可以启用某种选项,还是以块的形式进行更新的标准方法?

我将补充一点,没有被混淆的记录没有任何区别特征,所以我想在循环中使用rownum是行不通的(我认为)

4 个答案:

答案 0 :(得分:5)

如果要更新表中的每一行,最好选择Create Table As Select,然后删除/截断原始表并使用新数据重新附加。如果您有分区选项,则可以将新表创建为具有单个分区的表,并将其与EXCHANGE PARTITION交换。

插入需要少量撤消,带有nologging的直接路径插入(/ + APPEND / hint)也不会产生太多重做。

使用任何一种机制,可能会有旧法价值的“法证”证据(例如,由于行移动而保留在撤消或分配给表格的“可用”空间中)。

答案 1 :(得分:2)

以下是未经测试的,但应该有效:

declare
  l_fetchsize number := 10000;
  cursor cur_getrows is
  select rowid, random_function(my_column)
    from my_table;

  type rowid_tbl_type      is table of urowid;
  type my_column_tbl_type  is table of my_table.my_column%type;

  rowid_tbl     rowid_tbl_type;
  my_column_tbl my_column_tbl_type;
begin

  open cur_getrows;
  loop
    fetch cur_getrows bulk collect  
      into rowid_tbl, my_column_tbl 
      limit l_fetchsize;
    exit when rowid_tbl.count = 0;

    forall i in rowid_tbl.first..rowid_tbl.last
      update my_table 
         set my_column = my_column_tbl(i)
       where rowid     = rowid_tbl(i);
    commit;
  end loop;
  close cur_getrows;
end;
/

这不是最佳效率 - 只需一次更新 - 但它会使用ROWID执行较小的用户可调节批量。

答案 2 :(得分:0)

我通过将主键映射到整数(mod n)来执行此操作,然后对每个x执行更新,其中0< = x< Ñ

例如,也许你不走运,主键是一个字符串。您可以使用自己喜欢的哈希函数对其进行哈希处理,并将其分为三个分区:

UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=0
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=1
UPDATE myTable SET a=doMyUpdate(a) WHERE MOD(ORA_HASH(ID), 3)=2

您可能有更多分区,并且可能希望将其置于循环中(使用一些提交)。

答案 3 :(得分:0)

如果我必须更新数百万条记录,我可能会选择不更新。

我更可能创建一个临时表,然后从旧表中插入数据,因为插入不会占用大量的重做空间并且需要更少的撤消。

CREATE TABLE new_table as select <do the update "here"> from old_table;

index new_table
grant on new table
add constraints on new_table
etc on new_table

drop table old_table
rename new_table to old_table;

你可以使用并行查询来做到这一点,并且对大多数生成非常的操作都进行了nologging 小重做,根本没有撤消 - 只需要更新一小部分时间 数据。