Oracle:插入select后,更新表

时间:2014-03-16 11:17:43

标签: sql oracle

我需要你对我的下面案例的建议。

  1. 我从维护中获取数据并插入到dataTable中,其中rownum< = some value

  2. 一旦所有数据都已插入数据表,我希望维护中的这些数据将更新状态。

  3. 问题是如果rownum超过500k,则需要大约10分钟。这次可能有另一个请求是拾取相同的数据。我怎么想阻止这个?

    下面是我的sql。

    insert into dataTable(id,num,status) select m.id,m.num,m.status from mainTable m where m.status = 'FREE' and rownum <= 100000;
    
    update mainTable m set m.status = 'RESERVED' where m.num in (select d.num from dataTable where d.status = 'FREE');
    

    我做了一些研究,但我不知道是否需要使用select for updatemerge声明?

2 个答案:

答案 0 :(得分:1)

您无法使用MERGE,因为您只能插入或更新目标表。我猜这个问题要么是dataTable中列STATUS的选择性,要么mainTable中列NUM的选择性。

无论哪种方式, if 你只想更新mainTable中你刚刚插入mainTable的那些行,最简单的事情就是记住您刚刚插入并更新的内容。 BULK COLLECT似乎很合适。

declare

   cursor c_all is
     select rowid as rid, id, num, status
       from maintable
      where status = 'FREE' 
        and rownum <= 100000;

   type t__all is table of c_all%rowtype index by binary_integer;
   t_all t__all;

begin

   open c_all;
   loop
      fetch c_all bulk collect into t_all limit 10000;

      forall i in t_all.first .. t_all.last
         insert into datatable (id, num, status)
         values (t_all(i).id, t_all(i).num, t_all(i.status));

      forall i in t_all.first .. t_all.last
         update maintable
            set status = 'RESERVED' 
          where rowid t_all(i).rid;

   end loop;
   commit;
   close c_all;

end;
/

等同于您的查询,它假定maintable在NUM上是唯一的。如果它在ID上是唯一的,我会将UPDATE更改为MERGE(它更干净)并从光标中删除ROWID列:

forall i in t_all.first .. t_all.last
   merge into maintable m
   using ( select t_all(i).num from dual ) d
      on ( m.num = d.num )
    when matched then
         update
            set m.status = 'RESERVED'

正如我所写,如果问题是列/索引的选择性,你需要发布解释计划,索引等。

答案 1 :(得分:0)

我认为您在更新查询中使用EXISTS交换使用in会更好,它会更快:

update mainTable m 
set m.status = 'RESERVED' 
where exists (select * from dataTable where m.num = d.num and d.status = 'FREE');