以下存储过程从程序上看没什么问题,但是我来描述 一下问题:
1)TA723008 简称A表,TA723003_prepare简称B表。
2)A表里面有4千万条以上的数据,B表里面有1万条以上的数据,现在要对A表的某字段更新,匹配条件是A表中的日期为20071231之前的。然后就是拿A表中的某个字段去关联B表的字段,得到B表中的中文名然后更新到A表中去。
可是因为客观原因,不可能让一个存储过程跑一个晚上还在更新,因为按照以下的程序是一个笛卡尔乘积,拿一个表的全表扫描去匹配另一个表的全表扫描。
3)程序详解:逐条更新,然后通过计数器每更新1万条就commit一次。
希望有人能提出有建设性的方案来解决笛卡尔乘积 然后又能满足以上所说功能。不甚感激!!!!PROCEDURE R_MOVE_TA723008(OI_FLAG OUT INTEGER, --0 成功, -1 失败
                            OS_MESG OUT VARCHAR2 --出错详细信息
                            ) IS
    VI_COUNT     INTEGER := 0; --计数器
    VI_COUNT_all INTEGER := 0; --计数器
    CURSOR CUR_TA723008 IS
      SELECT ROWID, T.*
        FROM BIFT.TA723008 T
       WHERE T.TA723008002 <= '20071231'
         AND t.ta723008015 IS NULL; 
  
  BEGIN
    OI_FLAG := 0;
    OS_MESG := '更新开始';
  
    FOR VT_TA723008 IN CUR_TA723008 LOOP
      UPDATE TA723008
         SET TA723008015 = (SELECT TA723003007
                              FROM TA723003_PREPARE
                             WHERE TA723003_PREPARE.TA723003005 = TA723008009
                               AND ROWNUM = 1)
       WHERE TA723008.ROWID = VT_TA723008.ROWID;
    
      VI_COUNT     := VI_COUNT + 1;
      VI_COUNT_all := VI_COUNT_all + 1;
      IF (VI_COUNT >= 10000) THEN
        COMMIT;
        VI_COUNT := 0;
      END IF;
    END LOOP;
       OI_FLAG := 0;
    OS_MESG := '更新结束';
    COMMIT;
  EXCEPTION
    WHEN OTHERS THEN
      OI_FLAG := 1;
      OS_MESG := SUBSTRB(OS_MESG || '时出错! 错误代码:' || SQLCODE || ',错误信息:' ||
                         SQLERRM,
                         1,
                         400);
    
      RETURN;
    
  END R_MOVE_TA723008;

解决方案 »

  1.   

    CURSOR CUR_TA723008 IS 
          SELECT ROWID, T.* 
            FROM BIFT.TA723008 T 
          WHERE T.TA723008002 <= '20071231' 
            AND t.ta723008015 IS NULL; 这里游标为什么要取出表里的所有列呢?
    只取出要比较的那一列不就好了么 在这列上加上索引
      

  2.   

    楼主你去百度一下merge into不知道你们试过没有
    你这种情况也许用得到
      

  3.   

    楼主可以考虑下按天更新。用job在晚上没人工作的时候调用存储过程去执行update
      

  4.   

     UPDATE TA723008 
            SET TA723008015 = (SELECT TA723003007 
                                  FROM TA723003_PREPARE 
                                WHERE TA723003_PREPARE.TA723003005 = TA723008009 
                                  AND ROWNUM = 1) 
          WHERE TA723008.ROWID = VT_TA723008.ROWID; 所有字段都要更新?
    这里好像你只更新了TA723008015这一个字段而已啊
      

  5.   

    如果是一行的所有列都需要更新,那么不能用merge了,以为关联条件列也会被更新。我想的是既然关联条件TA723003_PREPARE.TA723003005的值有很多重复,你可以建一个视图先去重,
    select min(c1),min(c2),... from TA723003_PREPARE t1 group by TA723003005;该表1万条数据也不多,而且既然你在更新时使用rownum <= 1,说明这些值应该都是一致或相似的,随便用哪个值更新A表都可以,所以select后面的全部列都加上Min应该没关系。
      

  6.   

    补充一下,去重之后,在A表关联条件那一列加索引然后使用for all批量更新。
      

  7.   

    SELECT ROWID, T.*
    FROM BIFT.TA723008 T
    WHERE T.TA723008002 <= '20071231'
    AND t.ta723008015 IS NULL; 这样选出来太多行了,把表B连接进来