用 PL/SQL 
    

解决方案 »

  1.   

    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表将很快。
      

  2.   

    对A,B表分别建立分区,oracle中心非常赞成对大容量表建立分区
    参考:
    http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96524/c12parti.htm#464767
      

  3.   

    to:shi97521601(shi), beckhambobo(beckham):
    “一条语句实现时每udpate a表的一行都要遍历一下b表”这句我知道,
    为什么该过程只需遍厉一次b表?
    另外用游标是不是会先把所有的数据都放在回滚段中呢?oracle为一条语句分配
    回滚段的时候,采用什么样的算法?能指定回滚段么?()
      

  4.   

    同意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.
      

  5.   

    使用NOLOGGING选项:
    NOLOGGING选项因为不写日志,所以大大提高了性能,比不使用NOLOGGING选项大约会节省70%的时间。UPDATE 表名 NOLOGGING SET ...
      

  6.   

    注意,NOLOGGING 选项使用后,不能会滚!!
      

  7.   

    该修改用过程方法解决是非常可行的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过程,节省的时间是可以算出来的
      

  8.   

    不好意思刚才代码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;
      

  9.   

    1.如果表上有索引,使用nologging选项不能明显提高速度,也不能
       减小重做日志,因为维护索引需要产生大量的重做日志. 2. beckhamboo和我提出的方案都是可行的,只是角度不同而已。
        对表进行分区是处理大数据的好方案之一。单纯从sql的角度
        来看问题,虽然能解决目前的问题,但是随着表的数据量的增长,
        肯定会引发新的问题。因此,我个人认为解决诸如大数据量的更新,
        删除等比较现实的问题时,先优化存储结构是必须要考虑的。 3. "写from的时候,数据量大的表要放在前,小的放在后"这条原则 
        只是在优化器模式为rbo时有效,如果为cbo,它会自己评估查询代价.
      

  10.   

    请教
    如果有b,c,d...表要更新a表的某个字段又改怎么办?
      

  11.   

    首先非常感谢大家的参与、指点,请大家接着在这讨论,为了表示我的感谢,
    我将另外开新的文章给分。"写from的时候,数据量大的表要放在前,小的放在后",但是据我所知,应该刚好相反,
    特别是加上hint /*+ordered*/的时候.to:leecooper0918(爱一个人好难) 
    cbo比rbo更先进,效果更好,对吗? 你有更多的有关hint的文档资料么?
      

  12.   

    to leecooper0918(爱一个人好难)
    "写from的时候,数据量大的表要放在前,小的放在后"这条原则 
        只是在优化器模式为rbo时有效,如果为cbo,它会自己评估查询代价.
    说的对,cbo有自己的分析器,但普通的应用都是rbo的,遵循这个原则只有好处没有坏处,但具体情况,具体分析。
      

  13.   

    Oracle推荐的方式是使用CBO,而且从未来的某个版本开始(可能是10G)
    将不再支持rbo.
      

  14.   


    shi97521601(shi)
    beckhambobo(beckham)
    leecooper0918(爱一个人好难)
    bluewin99(蓝风)

    http://expert.csdn.net/Expert/topic/2612/2612946.xml?temp=.2544062
    接分