我需要你对我的下面案例的建议。
我从维护中获取数据并插入到dataTable中,其中rownum< = some value
一旦所有数据都已插入数据表,我希望维护中的这些数据将更新状态。
问题是如果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 update
或merge
声明?
答案 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');