简体   繁体   English

Oracle:插入select后,更新表

[英]Oracle : after insert into select, update the table

I need your advice to my below case. 对于以下情况,我需要您的建议。

  1. I get data from maintable and insert into dataTable where rownum <= some value 我从主表获取数据并插入到dataTable中,其中rownum <=一些值

  2. once all data already insert into datatable, i want this data in maintable will update the staus. 一旦所有数据都已经插入到数据表中,我希望主表中的数据将更新状态。

The problem is if the rownum more than 500k, it take about 10 minutes. 问题是,如果rownum超过500k,则大约需要10分钟。 This time there could be another request was pickup the same data. 这次可能还有另一个请求要提取相同的数据。 How i want to prevent this? 我要如何防止这种情况?

Below is my sql. 下面是我的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');

I do some research, but i dont know whether i need to use the select for update or merge statement? 我做了一些研究,但是我不知道我是否需要使用select for updatemerge语句?

You can't use MERGE, as you can only insert into or update the target table. 您不能使用MERGE,因为您只能插入或更新目标表。 I would guess that the problem is either the selectivity of the column STATUS in dataTable or of the column NUM in mainTable . 我想问题可能是dataTable中的STATUS列或mainTable中的NUM列的mainTable

Either way, if you only want to update those rows in mainTable that you've just inserted into mainTable the simplest thing to do would be to remember what you've just inserted and update that. 无论哪种方式, 如果只想更新刚刚插入到mainTable中的mainTable中的行,那么最简单的操作就是记住刚刚插入的行并进行更新。 A BULK COLLECT seems apposite. 批量收集似乎合适。

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

This is not equivalent to your query, it assumes that maintable is unique on NUM. 并不等同于您的查询,它假定maintable在NUM上是唯一的。 If it unique on ID I would change the UPDATE to a MERGE (it's cleaner) and remove the ROWID column from the cursor: 如果它在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'

As I've written though, if the problem is the selectivity of the columns/indexing you need to post the explain plan, indexes etc. 如我所写,如果问题是列/索引的选择性,则需要发布解释计划,索引等。

I think that it is better that you use EXISTS exchange of using in in your update query, it is so faster: 我认为最好在更新查询中使用EXISTS交换使用in这样会更快:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM