因为业务需要对一张大表的一个列值进行update更新,表中有数据一亿多条,为了更新这一亿多条数据,我做了一下尝试,给各位同学留个前车之鉴。

表名:test

列名:name varchar2(50)

方法一:

直接对大表update,

语句:update test set name=replace(name,chr(13),'');

结果:执行12个小时候,sql仍未执行完成,于是在执行12个小时之后,我把这个交易kill 了;

后果:最终耗费了48小时来完成数据回滚,给数据库带来了严重的的压力,同时造成了大量的锁等待,结局很悲惨。

方法二:

吸收了方法一的教训,一次修改的话,undo数据太大,对数据库性能有严重的影响,书写了一个存储过程,每一万条数据提交一次,同时新建一张表t1和sequence sq_test,记录已经修改的条数,sql如下:

CREATE OR REPLACE PROCEDURE UpdateBigTableRecord AS

 CURSOR c_cursor IS

   select rowid from test;

 v_rowid varchar(30);

 x       number := 0;

 y       number(30);

BEGIN

 OPEN c_cursor;

 LOOP

   FETCH c_cursor

     into v_rowid;

   EXIT WHEN c_cursor %NOTFOUND;

   update test

      set name = replace(name, chr(13), '')

    where rowid = v_rowid;

  insert into t1(id) values (sq_test.nextval);

   x := x + 1;

   IF x > 10000 THEN

     COMMIT;

     x := 0;

   END IF;

 END LOOP;

 CLOSE c_cursor;

EXCEPTION

 WHEN OTHERS THEN

   ROLLBACK;

   COMMIT;

END;

/

经过测过,此方法明显优于第一种方法,可以及时的释放锁资源,同时可以查看数据修改进度,经过测试,update速度约为每小时100万,这个速度 用来修改一亿条数据的话,估计需要100个小时,大概是4天4夜的时间。

结果:方法不适用,取消了

后果:又给数据库增加了undo压力

附带影响:磁盘阵列的IO等待严重,以至于后来在增加表空间时,速度缓慢,新增5M的表空间,耗时五分钟,大家可以想象一下大量的undo带来的后果,建议大家以后尽量回滚事物,尤其是对待一些大的事务。

方法三:

以上两种方法都是通过sql 使用update 来更新表中的数据,这种更新在带来大量的undo的同时也带来大量的redo,且速度缓慢。

最终通过下面的方法解决问题,create table as select..

sql如下:

create table BK_TEST

(

 id,

 name,

) parallel (degree 2)

as

select

id,    

replace(name, chr(13), '') name ,

from   test nologging;


整个过程耗时00:03:59.66

方法四:

如果你觉得第三种方法创建新表将会耗费一些磁盘IO和磁盘空间,不愿意这么做,还有第四种方法:

在表之上创建视图。

sql:

create or replace view v1_test(name) as  select  replace(name, chr(13), '') name from test;

alter table test add primary key(name);