大表的update更新(转)

本文分享了一次对一亿多条数据的大表更新经验,详细对比了直接更新、存储过程分批更新及创建新表三种方法的效果。最终采用创建新表的方式,仅用4分钟完成全部更新,大幅提升了效率。

因为业务需要对一张大表的一个列值进行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);

### 使用 `JOIN` 更新 A 字段为 B 对应字段 若需要将 A 中的某些字段更新为 B 中对应的字段值,可以使用 `UPDATE` 语句结合 `JOIN` 操作。该方法适用于多数支持多更新的数据库系统(如 MySQL)。 ```sql UPDATE tableA a INNER JOIN tableB b ON a.b_rel_field = b.id SET a.fieldA = b.fieldA, a.fieldB = b.fieldB; ``` 此语句通过 `INNER JOIN` 将 `tableA` 和 `tableB` 根据指定条件连接,并将 `tableA` 中的 `fieldA` 和 `fieldB` 字段更新为 `tableB` 中的对应字段值 [^3]。 --- ### 使用子查询更新 A 字段为 B 对应字段 在 Oracle 等不直接支持多更新的数据库中,可以通过子查询方式实现类似功能: ```sql UPDATE tableA a SET a.fieldA = (SELECT b.fieldA FROM tableB b WHERE a.b_rel_field = b.id), a.fieldB = (SELECT b.fieldB FROM tableB b WHERE a.b_rel_field = b.id) WHERE EXISTS (SELECT 1 FROM tableB b WHERE a.b_rel_field = b.id); ``` 该语句确保只有当 `tableB` 中存在匹配记录时才会执行更新操作,避免对非目标数据造成影响 [^2]。 --- ### 更新多个字段并限制更新范围 如果需要一次性更新多个字段,并且希望限制更新的行数或添加额外条件,可以扩展上述语法: ```sql UPDATE ( SELECT a.fieldA AS a_val, b.fieldA AS b_val, a.fieldB AS a_val2, b.fieldB AS b_val2 FROM tableA a INNER JOIN tableB b ON a.b_rel_field = b.id ) SET a_val = b_val, a_val2 = b_val2; ``` 这种方式适用于 Oracle 数据库,通过定义一个可更新的视图来完成跨更新操作 [^4]。 --- ### 注意事项 - **数据类型一致性**:确保更新字段的数据类型一致,否则可能会导致错误,必要时可通过 `CAST()` 或 `CONVERT()` 函数进行类型换 [^4]。 - **验证更新逻辑**:在执行 `UPDATE` 操作前,建议先用 `SELECT` 查询验证连接条件和目标字段是否正确,以防止误更新 [^2]。 - **分批次处理**:如果更新的数据量较或涉及多个,可考虑分批次处理,以减少锁时间和事务日志压力 [^3]。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值