oracle 根据rowid分片

对于update,delete操作,如果分区表,可以分区进行操作;
如果是一个非分区的大表,那么此时的容易引发UNDO不够,如果连接中断的话,那么回滚必然很耗时间;
所以,这里可以对非分区的大表进行rowid分片;
先验证分片数量是否正确:
declare
  cursor c_get_rid is
       select 
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID,0
     ) rid1,
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID+aa.BLOCKS-1,999) rid2
     from dba_extents aa,dba_objects bb
     where aa.segment_name=bb.OBJECT_NAME
     and aa.owner=bb.OWNER
     and aa.owner='SCOTT'
     and aa.segment_name=upper('TAB1') ;

   v_count pls_integer:=0; 
   v_sum pls_integer:=0; 

begin
   for v_row in c_get_rid loop
       select count(1) into v_count from tab1 a where  rowid>=v_row.rid1 and rowid<=v_row.rid2; 
       v_sum:=v_sum+ v_count;
   end loop;
   dbms_output.put_line('分片统计行数:'||v_sum);  
   select count(1) into v_sum from tab1;
   dbms_output.put_line('实际统计行数:'||v_sum);    
end;
发现是一样的;

--delete操作

grant select on dba_extents to scott;
grant select on dba_objects to scott;  
/*
为某个表自定义分割片数
p_range:分区的个数
*/ 
create or replace procedure p_rowid(p_table_name varchar2,p_range pls_integer,p_id pls_integer)
as
  cursor c_get_rid is
     select 
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID,0
     ) rid1, 
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID+aa.BLOCKS-1,999) rid2
     from dba_extents aa,dba_objects bb
     where aa.segment_name=bb.OBJECT_NAME
     and aa.owner=bb.OWNER
     and aa.owner='SCOTT'
     and aa.segment_name=upper(p_table_name) 
     and mod(aa.EXTENT_ID,p_range)=p_id;
     v_sql varchar2(4000);

begin

    for v_row in c_get_rid loop
       v_sql:='delete '||p_table_name||' where rowid between :1 and :2';
       execute immediate v_sql using v_row.rid1,v_row.rid2;
    end loop;    
    dbms_output.put_line('ok');
    commit;
exception
  when others then
   dbms_output.put_line(substr(sqlerrm,1,200)||dbms_utility.format_error_backtrace);  
end;
/

测试:在4个窗口执行;
exec p_rowid('tab1',4,2);

但是上面,当你在不同sql窗口执行时,无法保证数据的一致性,于是可以创建一个临时表,再结合批量更新 ,
最快的更新方式就这样诞生了…

   drop table   tab1_rowid;
   create table tab1_rowid
   as
     select 
     rownum rn,
     aa.EXTENT_ID,
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID,0
     ) rid1, 
     dbms_rowid.rowid_create(
      1,bb.DATA_OBJECT_ID,aa.relative_fno,aa.BLOCK_ID+aa.BLOCKS-1,999) rid2
     from dba_extents aa,dba_objects bb
     where aa.segment_name=bb.OBJECT_NAME
     and aa.owner=bb.OWNER
     and aa.owner='SCOTT'
     and aa.segment_name=upper('tab1');

--rowid分片加批量更新  最快的方式
create or replace procedure p_tab1_rowid(p_id pls_integer)
as
  cursor c_get_rid is
  select aa.rid1,aa.rid2 from tab1_rowid aa where  mod(aa.rn,8)=p_id;     
  v_min_rowid_tab dbms_sql.Urowid_Table; 
  v_max_rowid_tab dbms_sql.Urowid_Table;

  v_sql varchar2(4000);
  v_limit pls_integer:=1000;
begin
   open c_get_rid; 
    loop   
    fetch   c_get_rid  bulk collect into v_min_rowid_tab,v_max_rowid_tab limit  v_limit;
      forall x in  1 .. v_min_rowid_tab.count
         update tab1 t set t.object_name='aaa' where rowid between v_min_rowid_tab(x) and v_max_rowid_tab(x);  
      exit when c_get_rid%notfound;
    end loop;
   close  c_get_rid;
exception
  when others then  
   --如果有异常回滚所有  
   rollback;
dbms_output.put_line(substr(sqlerrm,1,200)||dbms_utility.format_error_backtrace);  
end;
/


--8个窗口执行
begin
  p_tab1_rowid(0);  
...
  p_tab1_rowid(7);
end;

分片参考来源:落落老师

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值