create view tmp(id,total) as select id,sum(total) as total from b order by id;create index idx_a on a(id); create index idx_b on b(id);declare cursor cur_tmp is select * from tmp; begin for v_tmp in cur_tmp loop update a set total = v_tmp.total where a.id = v_tmp.id; end loop; end;分析: 一条语句实现时每udpate b表的一行都要遍历一下b表,而 改为以上过程后只需遍厉一次b 表,而通过索引查找a表将很快。
同意beckhambobo的看法,不赞成shi97521601的看法,因为用 游标操作是非常耗费系统资源的,特别是用游标执行 select * from ... 这样的子句:一种办法: set transaction use ROLLBACK SEGMENT RBSNAME; update ... where ... COMMIT;上面的做法是为update操作指定一个私有的,大的回滚段。更好的做法(from asktom.oracle.com)case 1: create table new_table unrecoverable as select * from old_table where ....; drop table old_table; rename new_table to old_table; create index old_table_idx1 on old_table(c1,c2) unrecoverable parallel 5; ..... NO log on that, just move the data to a new table, drop/rename old/new, create indexes as fast as possible without log.case2: partition the data, do a parallel delete. Each partition will use its own rollback segment, each will run in parallel.case3: partition the data so that you can do a DROP partition instead of DELETE.
使用NOLOGGING选项: NOLOGGING选项因为不写日志,所以大大提高了性能,比不使用NOLOGGING选项大约会节省70%的时间。UPDATE 表名 NOLOGGING SET ...
注意,NOLOGGING 选项使用后,不能会滚!!
该修改用过程方法解决是非常可行的shi97521601(shi) 的方法我赞同,前面N为同志讨论的东西应该不属于本讨论的范畴,不实际也没实际解决问题,shi97521601(shi)那个存储过程可以稍微改改 declare cursor cur_tmp is select b.id x1,sum(total) x2 from b,a where b.id=a.idbegin group by b.id for v_tmp in cur_tmp loop update a set total = v_tmp.x2 where a.id = v_tmp.x1; end loop; end;这样写效率大大提高,同时b表有上千万数据,说明你们的服务器非常的强壮,执行select b.id x1,sum(total) x2 from b,a where b.id=a.idbegin group by b.id 非常快,这样只需要对刚才的语句的结果遍历一次,同时,该结果是在a表基础上产生,所以记录也只有100万行,执行速度应该是可以大大提高,写from的时候,数据量大的表要放在前,小的放在后同时你开始写的sql语句,慢是因为,a表每走一行进行修改是,都要对b表进行一次全表的sum,单独执行一次b表的sum是0。1秒的话,你的语句就要执行sum语句100万次,100万×0。1也是个非常庞大的消耗。用以上过程写,避免了100万次的sum过程,节省的时间是可以算出来的
不好意思刚才代码copy错误一下是代码: declare cursor cur_tmp is select b.id x1,sum(total) x2 from b,a where b.id=a.id group by b.id begin for v_tmp in cur_tmp loop update a set total = v_tmp.x2 where a.id = v_tmp.x1; end loop; end;
create index idx_b on b(id);declare
cursor cur_tmp is
select * from tmp;
begin
for v_tmp in cur_tmp loop
update a set total = v_tmp.total where a.id = v_tmp.id;
end loop;
end;分析:
一条语句实现时每udpate b表的一行都要遍历一下b表,而 改为以上过程后只需遍厉一次b 表,而通过索引查找a表将很快。
参考:
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c12parti.htm#464767
“一条语句实现时每udpate a表的一行都要遍历一下b表”这句我知道,
为什么该过程只需遍厉一次b表?
另外用游标是不是会先把所有的数据都放在回滚段中呢?oracle为一条语句分配
回滚段的时候,采用什么样的算法?能指定回滚段么?()
游标操作是非常耗费系统资源的,特别是用游标执行 select * from ...
这样的子句:一种办法:
set transaction use ROLLBACK SEGMENT RBSNAME;
update ... where ...
COMMIT;上面的做法是为update操作指定一个私有的,大的回滚段。更好的做法(from asktom.oracle.com)case 1:
create table new_table unrecoverable as select * from old_table where ....;
drop table old_table;
rename new_table to old_table;
create index old_table_idx1 on old_table(c1,c2) unrecoverable parallel 5;
..... NO log on that, just move the data to a new table, drop/rename old/new,
create indexes as fast as possible without log.case2:
partition the data, do a parallel delete. Each partition will use its
own rollback segment, each will run in parallel.case3:
partition the data so that you can do a DROP partition instead of DELETE.
NOLOGGING选项因为不写日志,所以大大提高了性能,比不使用NOLOGGING选项大约会节省70%的时间。UPDATE 表名 NOLOGGING SET ...
declare
cursor cur_tmp is
select b.id x1,sum(total) x2 from b,a where b.id=a.idbegin group by b.id
for v_tmp in cur_tmp loop
update a set total = v_tmp.x2 where a.id = v_tmp.x1;
end loop;
end;这样写效率大大提高,同时b表有上千万数据,说明你们的服务器非常的强壮,执行select b.id x1,sum(total) x2 from b,a where b.id=a.idbegin group by b.id
非常快,这样只需要对刚才的语句的结果遍历一次,同时,该结果是在a表基础上产生,所以记录也只有100万行,执行速度应该是可以大大提高,写from的时候,数据量大的表要放在前,小的放在后同时你开始写的sql语句,慢是因为,a表每走一行进行修改是,都要对b表进行一次全表的sum,单独执行一次b表的sum是0。1秒的话,你的语句就要执行sum语句100万次,100万×0。1也是个非常庞大的消耗。用以上过程写,避免了100万次的sum过程,节省的时间是可以算出来的
declare
cursor cur_tmp is
select b.id x1,sum(total) x2 from b,a where b.id=a.id group by b.id
begin
for v_tmp in cur_tmp loop
update a set total = v_tmp.x2 where a.id = v_tmp.x1;
end loop;
end;
减小重做日志,因为维护索引需要产生大量的重做日志. 2. beckhamboo和我提出的方案都是可行的,只是角度不同而已。
对表进行分区是处理大数据的好方案之一。单纯从sql的角度
来看问题,虽然能解决目前的问题,但是随着表的数据量的增长,
肯定会引发新的问题。因此,我个人认为解决诸如大数据量的更新,
删除等比较现实的问题时,先优化存储结构是必须要考虑的。 3. "写from的时候,数据量大的表要放在前,小的放在后"这条原则
只是在优化器模式为rbo时有效,如果为cbo,它会自己评估查询代价.
如果有b,c,d...表要更新a表的某个字段又改怎么办?
我将另外开新的文章给分。"写from的时候,数据量大的表要放在前,小的放在后",但是据我所知,应该刚好相反,
特别是加上hint /*+ordered*/的时候.to:leecooper0918(爱一个人好难)
cbo比rbo更先进,效果更好,对吗? 你有更多的有关hint的文档资料么?
"写from的时候,数据量大的表要放在前,小的放在后"这条原则
只是在优化器模式为rbo时有效,如果为cbo,它会自己评估查询代价.
说的对,cbo有自己的分析器,但普通的应用都是rbo的,遵循这个原则只有好处没有坏处,但具体情况,具体分析。
将不再支持rbo.
shi97521601(shi)
beckhambobo(beckham)
leecooper0918(爱一个人好难)
bluewin99(蓝风)
到
http://expert.csdn.net/Expert/topic/2612/2612946.xml?temp=.2544062
接分