表A  记录3600W行  表大小大概2.4G
主要字段
serv_id number
serv_type_id number
其中serv_id是主键,serv_type_id为空,需要update表B  记录4200W行  表大小大概7.3G
主要字段
serv_id number
serv_seq_nbr number
serv_type_id
其中serv_id和serv_seq_nbr是联合主键.
同一个serv_id对应多个serv_seq_nbr,serv_seq_nbr分别为0、1、2、……N,
现在需要做的就是,UPDATE A 表 的serv_type_id的字段,根据serv_id在B表中找到对应的serv_id记录并以serv_seq_nbr为最大值的那条所对应的serv_type_id.
现在更新超慢,用函数+批量绑定+原子处理都不能达到理想效果,估计更新时间30个小时。
注:写了一个根据serv_id取serv_type_id的小函数,游标批量绑定以10000条一批
有没有什么好办法?

解决方案 »

  1.   

    我的思路:FOR Batch_Counter IN 1..3600 LOOP
     UPDATE A
     SET serv_type_id=GET_SERV_TYPE_ID(serv_id)
     WHERE serv_type_id IS NULL
     AND serv_id BETWEEN (Batch_Counter-1)*10000 AND Batch_Counter*10000
    END LOOP;如果你函数 GET_SERV_TYPE_ID 效率可以的话,那么这种方式应该还行,因为用到了主键索引的局部扫描。你可以先把循环的上下界都改成1,也就是说只执行一次循环,更新10000条,看看需要多少时间
      

  2.   

    建议将B表的serv_type_id设为主键··另外两个分别建普通索引试试
      

  3.   

    写了个过程,你可以试试,只测试了100万左右数据,速度挺快的,几千万数据还没条件测试,不过还不至于30小时吧,不能说一定管用,但是可以借鉴下,我也是网上看到的CREATE OR REPLACE PROCEDURE bulk_update IS
      TYPE t_serv_id IS TABLE OF testb.serv_id%TYPE;
      TYPE t_serv_seq_nbr IS TABLE OF testb.serv_seq_nbr%TYPE;
      -- 定义保存源数据的数组
      arr_serv_id t_serv_id;
      arr_serv_seq_nbr t_serv_seq_nbr;
      -- 更新的数据源,下面用游标批量读取
      CURSOR c IS
        SELECT serv_id, MAX(serv_seq_nbr) serv_seq_nbr FROM testb GROUP BY serv_id;
    BEGIN
      OPEN c;
      LOOP
          -- 批量更新,一次更新1000条数据,防止数据量过大内存溢出
          fetch c bulk collect into arr_serv_id, arr_serv_seq_nbr LIMIT 100;
          -- 这里用forall比for效率高很多
          FORALL i IN 1 .. arr_serv_id.COUNT
           UPDATE testa SET serv_type_id = arr_serv_seq_nbr(i) WHERE serv_id = arr_serv_id(i);
          -- 循环退出,注意不要放在循环前面
          
          COMMIT;
          exit when c%NOTFOUND;
          
      END LOOP;
      
      --COMMIT;END bulk_update;