对于大表的update,delete,很容易引起undo不够的问题,特别是在一个session里面运行的时候,或者由于其他原因导致的回滚操作,这个就比较苦逼了,如果是分区表,可能影响稍微小一点,我们可以按照分区来进行更新,按照分区来进行delete。对于不是分区表的情况,就可以用rowid切片,然后开启多个进程并行处理,这样既能提升不少的速度,也能减少undo,防止死事物恢复太慢。
我这里有test_b表,表中有2793440条数据,我们简单的按照rowid切片对表进行处理
SQL> select count(*) from test_b; COUNT(*) -------- 2793440 select ‘where rowid between ‘‘‘ ||sys.dbms_rowid.rowid_create(1, d.oid, c.fid1, c.bid1, 0) ||‘‘‘ and ‘‘‘ ||sys.dbms_rowid.rowid_create(1, d.oid, c.fid2, c.bid2, 9999) || ‘‘‘‘ ||‘;‘ from (select distinct b.rn, first_value(a.fid) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) fid1, last_value(a.fid) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) fid2, first_value(decode(sign(range2 - range1), 1, a.bid + ((b.rn - a.range1) * a.chunks1), a.bid)) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) bid1, last_value(decode(sign(range2 - range1), 1, a.bid + ((b.rn - a.range1 + 1) * a.chunks1) - 1, (a.bid + a.blocks - 1))) over(partition by b.rn order by a.fid, a.bid rows between unbounded preceding and unbounded following) bid2 from (select fid, bid, blocks, chunks1, 19 trunc((sum2 - blocks + 1 - 0.1) / chunks1) range1, trunc((sum2 - 0.1) / chunks1) range2 from (select /*+ rule */ relative_fno fid, block_id bid, blocks, sum(blocks) over() sum1, trunc((sum(blocks) over()) / &&rowid_ranges) chunks1, sum(blocks) over(order by relative_fno, block_id) sum2 from dba_extents where segment_name = upper(‘&&segment_name‘) and owner = upper(‘&&owner‘)) where sum1 > &&rowid_ranges) a, (select rownum - 1 rn from dual connect by level <= &&rowid_ranges) b where b.rn between a.range1 and a.range2) c, (select max(data_object_id) oid from dba_objects where object_name = upper(‘&&segment_name‘) and owner = upper(‘&&owner‘) and data_object_id is not null) d Enter value for rowid_ranges: 15 old 26: trunc((sum(blocks) over()) / &&rowid_ranges) chunks1, new 26: trunc((sum(blocks) over()) / 15) chunks1, Enter value for segment_name: test_b old 29: where segment_name = upper(‘&&segment_name‘) new 29: where segment_name = upper(‘test_b‘) Enter value for owner: scott old 30: and owner = upper(‘&&owner‘)) new 30: and owner = upper(‘scott‘)) old 31: where sum1 > &&rowid_ranges) a, new 31: where sum1 > 15) a, old 34: connect by level <= &&rowid_ranges) b new 34: connect by level <= 15) b old 38: where object_name = upper(‘&&segment_name‘) new 38: where object_name = upper(‘test_b‘) old 39: and owner = upper(‘&&owner‘) new 39: and owner = upper(‘scott‘)
‘WHEREROWIDBETWEEN‘‘‘||SYS.DBMS_ROWID.ROWID_CREATE(1,D.OID,C.FID1,------------------------------------------------------------------where rowid between ‘AAAqh3AAIAAAACIAAA‘ and ‘AAAqh3AAIAAABYpCcP‘;where rowid between ‘AAAqh3AAIAAABYqAAA‘ and ‘AAAqh3AAIAAACCpCcP‘;where rowid between ‘AAAqh3AAIAAACCqAAA‘ and ‘AAAqh3AAIAAACspCcP‘;where rowid between ‘AAAqh3AAIAAACsqAAA‘ and ‘AAAqh3AAIAAADOpCcP‘;where rowid between ‘AAAqh3AAIAAADOqAAA‘ and ‘AAAqh3AAIAAAD+pCcP‘;where rowid between ‘AAAqh3AAIAAAD+qAAA‘ and ‘AAAqh3AAIAAAEepCcP‘;where rowid between ‘AAAqh3AAIAAAEeqAAA‘ and ‘AAAqh3AAIAAAFOpCcP‘;where rowid between ‘AAAqh3AAIAAAFOqAAA‘ and ‘AAAqh3AAIAAAF+pCcP‘;where rowid between ‘AAAqh3AAIAAAF+qAAA‘ and ‘AAAqh3AAIAAAGepCcP‘;where rowid between ‘AAAqh3AAIAAAGeqAAA‘ and ‘AAAqh3AAIAAAHOpCcP‘;where rowid between ‘AAAqh3AAIAAAHOqAAA‘ and ‘AAAqh3AAIAAAH+pCcP‘;where rowid between ‘AAAqh3AAIAAAH+qAAA‘ and ‘AAAqh3AAIAAAIepCcP‘;where rowid between ‘AAAqh3AAIAAAIeqAAA‘ and ‘AAAqh3AAIAAAJOpCcP‘;where rowid between ‘AAAqh3AAIAAAJOqAAA‘ and ‘AAAqh3AAIAAAJ+pCcP‘;where rowid between ‘AAAqh3AAIAAAJ+qAAA‘ and ‘AAAqh3AAIAAAKepCcP‘; 15 rows selected. Elapsed: 00:05:33.55
上面的例子,把test_b表分成15个rowid片,运行rowid切片sql的时候,需要传入3个参数,第一个是切片数量,第二个是切片对象,第三个是切片对象所属的对象,也就是owner,sql最终输出的结果可以看到,按照rowid对test_b表进行了切片,在update和delete的时候,分成15个session,加上并行处理,速度比直接update和delete快很多。
直接update操作:
SQL> update test_b set object_id=100; 2793440 rows updated. Elapsed: 00:24:19.65
花了24分钟 ,占用了大量的UNDO表空间
之后便是相同的时间的ROLLBACK,
可以查询回滚的速度:
SQL> select KTUXESIZ from x$ktuxe where KTUXESTA<>‘INACTIVE‘; KTUXESIZ-------- 85462
SQL> rollback; Rollback complete. Elapsed: 00:50:36.58 SQL> update test_b set object_id=100 where rowid between ‘AAAqh3AAIAAAACIAAA‘ and ‘AAAqh3AAIAAABYpCcP‘; 375065 rows updated. Elapsed: 00:01:47.92SQL> update /* +parallel(test_b 4) */ test_b set object_id=100 where rowid between ‘AAAqh3AAIAAABYqAAA‘ and ‘AAAqh3AAIAAACCpCcP‘; 185986 rows updated. Elapsed: 00:00:57.22
时间: 2024-11-22 20:35:35