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

Sql 具有超过1000万条记录的快速更新数据库,sql,database,oracle,plsql,toad,Sql,Database,Oracle,Plsql,Toad,我对SQL相当陌生,不知道是否有人可以帮助我 我有一个数据库,大约有1000万行 我需要制作一个脚本,查找包含一些空字段的记录,然后将其更新为某个值 执行一个简单的update语句的问题是,它会占用回滚空间 我在四处阅读,我需要使用批量收集和获取 我的想法是一次获取10000条记录,更新、提交并继续获取 我试着在谷歌上寻找例子,但我还没有找到任何东西 有什么帮助吗 谢谢 这就是我到目前为止所做的: DECLARE CURSOR rec_cur IS SELECT DATE_ORI

我对SQL相当陌生,不知道是否有人可以帮助我

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

我需要制作一个脚本,查找包含一些空字段的记录,然后将其更新为某个值

执行一个简单的update语句的问题是,它会占用回滚空间

我在四处阅读,我需要使用批量收集和获取

我的想法是一次获取10000条记录,更新、提交并继续获取

我试着在谷歌上寻找例子,但我还没有找到任何东西

有什么帮助吗

谢谢

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

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;

我想我明白你想做什么了。关于下面的代码与您的代码之间的差异,我想提出一些观点

您的forall循环将不使用索引。通过使用rowid更新您的表,这很容易解决。 通过在每次forall之后提交,您可以减少所需的撤销量;但如果出现问题,则更难回滚。虽然逻辑上,你的查询可以轻松地在中间重新启动,而不损害你的目标。 Rowid很小,一次至少收集25k;如果不是10万。 不能在Oracle中为空索引。关于stackoverflow有很多问题,您需要更多信息。在nvldate_origin上的函数索引,作为一个松散的示例,“x”将提高选择数据的速度。这也意味着您实际上不必使用表本身。您只能从索引中进行选择。 您的日期数据类型似乎是字符串。我保留了这个,但这不明智。 如果您可以让某人增加撤消表空间的大小,那么直接更新会更快。 假设根据您的评论,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开发人员中的工作示例

 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;
/

那么,您尝试了单个UPDATE语句,但它生成了一个错误?确切的错误是什么?如果错误是您的撤消空间不足,您是否要求DBA增加撤消空间?1000万行并不是很多-您的数据库的大小确实应该能够处理您想要增加的合理工作负载,而不是试图编写代码来节省几MB的磁盘空间。我认为您的做法是正确的。发布一些代码,可能会有人对其进行评论。数据库是一个生产服务器,所以我们还没有完成单个更新语句,但根据我的经验,它以前已经崩溃了…是否仍有可能以大容量获取方式执行此操作?我在底部添加了到目前为止的内容,我得到了以下错误:PLS-00435:DML语句没有绑定中的大容量不能在内部使用,因为您当前的代码没有真正意义。首先,rec_cur游标被定义为仅返回null:它不提供有关要更新的记录的任何信息。其次,您的更新在WHERE子句中没有任何内容将其限制为要更新的记录;它只是做完整的原始更新,包括所有记录。第三,我不认为这种方法会减少您所需的撤消空间,因为您的事务仍将和以前一样大。谢谢Ben!这似乎是一个很好的方法,出于某种原因,代码首先在t_rec。。t_rec.last loop PLS-00103:在期望一个following@xela_austin那是因为我犯了最常见的甲骨文错误。forall不需要循环;我已经更新了我的答案。有关更多文档,请参阅。再次感谢!现在它说ORA-01858:一个非数字字符被发现在一个数字的地方。。这种情况发生在将c_rec批量收集到t_rec limit 50000中@xela_austin,我的代码中没有错误。查看文档。我只能猜测您已经编写了50000个类型,或者没有将该类型创建为rowid类型等等。。。或者你的约会实际上是一个数字,而不是一个日期或一个字符。我检查了3个案例,但仍然没有运气。。我用的是50000而不是50000,类型是rowid…我用蟾蜍在桌子上做了一个描述,dat_origin Column类型是DATE…:/