昨晚更新了一批数据,用update的老办法耗时20多分,而用 merge into 不到2秒结束,效率真是天壤之别。具体见下:
用t_tmp_school(135868行)的birth 字段更新t_tmp_nt_customerdetail( 763119行) 的birthdate 字段,连接条件 t_tmp_school.id = t_tmp_nt_customerdetail.schoolid
--表结构
create table t_tmp_nt_customerdetail
(
customerid varchar2(15) not null,
doccategory varchar2(2) not null,
docnumber varchar2(20) not null,
birthdate varchar2(8),
...........
schoolid varchar2(60)
);
create table t_tmp_school
(
id varchar2(20),
company varchar2(100),
name varchar2(20),
birth varchar2(20)
);
--两个表的数据见下:
select count(1) from t_tmp_nt_customerdetail t; --763119
select count(1) from t_tmp_school; --135868
--为了验证结果,测试前先清空birthdate的值,网站空间,共更改 135879 行
update t_tmp_nt_customerdetail t
set t.birthdate = null
where t.schoolid is not null;
---实现的过程:
create or replace procedure p_tmp_update_customerdetail
is
v_begintran int := 0; -- 事务标志,初始值为0,香港空间,表示没有事务
v_errcode int;
v_errmsg varchar2(200); -- 处理异常变量
begin
-- 设置事务标志为1,表示开始事务
v_begintran := 1;
merge into t_tmp_nt_customerdetail t
using (select b.id, b.birth from t_tmp_school b where b.birth is not null) a
on (t.schoolid = a.id)
when matched then
update set t.birthdate = a.birth where t.schoolid is not null;
commit;
-- 提交事务并且置事务标志为0。
v_begintran := 0;
exception
when others then
-- 如果异常,回滚事务。
if v_begintran = 1 then
rollback;
end if;
v_errcode := sqlcode;
v_errmsg := substr(sqlerrm, 1, 150);
dbms_output.put_line(v_errcode);
dbms_output.put_line(v_errmsg);
end;
--执行过程,用时1.11秒
sql> exec p_tmp_update_customerdetail;
--再次验证结果,先前清空birthdate的值已经有了,返回 135879 行
select count(1) from t_tmp_nt_customerdetail t
where t.schoolid is not null
and t.birthdate is not null;
--而用下面类似的语句,这些数据执行了24分钟多:
update t_tmp_nt_customerdetail t
set t.birthdate = (select b.birth
from t_tmp_school b
where t.schoolid = b.id)
where t.schoolid =
(select c.id from t_tmp_school c where t.schoolid = c.id)
and t.schoolid is not null; ---注:为什么要写这个罗嗦的条件呢?因为没有这个条件就把整个表的数据全部更新了,因此必须写,虚拟主机,所以大家应该多实践,不要被一些表面现象所蒙蔽。
本文出自 “srsunbing” 博客,请务必保留此出处