Sh4m
Sh4m

Reputation: 1532

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

  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. This time there could be another request was pickup the same data. How i want to prevent this?

Below is my 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?

Upvotes: 0

Views: 521

Answers (2)

Ben
Ben

Reputation: 52913

You can't use MERGE, as you can only insert into or update the target table. I would guess that the problem is either the selectivity of the column STATUS in dataTable or of the column NUM in 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. 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. If it unique on ID I would change the UPDATE to a MERGE (it's cleaner) and remove the ROWID column from the cursor:

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.

Upvotes: 1

Hamidreza
Hamidreza

Reputation: 3128

I think that it is better that you use EXISTS exchange of using in in your update query, it is so faster:

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

Upvotes: 0

Related Questions