具有超过1000万条记录的快速更新数据库

时间:2012-02-14 19:55:16

标签: sql database oracle plsql toad

我对SQL很新,想知道是否有人可以帮助我。

我有一个大约有1000万行的数据库。

我需要创建一个脚本来查找具有一些NULL字段的记录,然后将其更新为某个值。

我做一个简单的更新语句时遇到的问题是它会破坏回滚空间。

我正在四处阅读,我需要使用BULK COLLECT AND FETCH。

我的想法是一次获取10,000条记录,更新,提交和继续提取。

我尝试在Google上查找示例,但我还没有找到任何内容。

任何帮助?

谢谢!

这是我到目前为止所做的:

DECLARE
    CURSOR rec_cur IS
    SELECT DATE_ORIGIN 
    FROM MAIN_TBL WHERE DATE_ORIGIN IS NULL;

    TYPE date_tab_t IS TABLE OF DATE;

    date_tab date_tab_t;

BEGIN
    OPEN rec_cur;
    LOOP
        FETCH rec_cur BULK COLLECT INTO date_tab LIMIT 1000;
        EXIT WHEN date_tab.COUNT() = 0;

        FORALL i IN 1 .. date_tab.COUNT
            UPDATE MAIN_TBL SET DATE_ORIGIN  = '23-JAN-2012' 
            WHERE DATE_ORIGIN IS NULL;

    END LOOP;
    CLOSE rec_cur;
END;

1 个答案:

答案 0 :(得分:3)

我想我知道你要做什么。关于以下代码与您之间的差异,我想提出一些观点。

  1. 您的forall循环不会使用索引。通过使用rowid更新您的表格,这很容易实现。
  2. 通过在每个forall之后提交,减少所需的撤消量;但如果出现问题,请更难以回滚。虽然从逻辑上讲,您的查询可以轻松地在中间重新启动,而不会损害您的目标。
  3. rowids很小,一次收集至少25k;如果不是100k。
  4. 您无法在Oracle中索引null。关于stackoverflow有很多问题,你需要更多的信息。像nvl(date_origin,'x')这样的函数索引作为一个松散的例子会提高你选择数据的速度。这也意味着你实际上不必使用表本身。您只能从索引中选择。
  5. 您的日期数据类型似乎是一个字符串。我保留了这个,但这不明智。
  6. 如果您可以让某人增加撤消表空间大小,那么直接更新会更快。
  7. 假设根据您的评论date_origin是一个日期,那么索引应该是这样的:

    nvl(date_origin,to_date('absolute_minimum_date_in_Oracle_as_a_string','yyyymmdd'))
    

    我目前无法访问数据库,但要查找amdiOaas运行以下查询:

    select to_date('0001','yyyy') from dual;
    

    它应该为你提出一个有用的错误。


    PL / SQL Developer中的工作示例。

     create table main_tbl as
      select cast( null as date ) as date_origin
        from all_objects
             ;
    
    create index i_main_tbl
       on main_tbl ( nvl( to_date(date_origin,'yyyy-mm-dd')
                        , to_date('0001-01-01' ,'yyyy-mm-dd') )
                    )
          ;
    
    declare
    
       cursor c_rec is
        select rowid
          from main_tbl
         where nvl(date_origin,to_date('0001-01-01','yyyy-mm-dd')) 
                   = to_date('0001-01-01','yyyy-mm-dd')
              ;
    
       type t__rec is table of rowid index by binary_integer;
       t_rec t__rec;
    
    begin
    
       open c_rec;
       loop
    
          fetch c_rec bulk collect into t_rec limit 50000;
    
          exit when t_rec.count = 0;
    
          forall i in t_rec.first .. t_rec.last
             update main_tbl
                set date_origin = to_date('23-JAN-2012','DD-MON-YYYY')
              where rowid = t_rec(i)
                    ;
             commit ;
    
       end loop;
       close c_rec;
    end;
    /