由于业务调整需要,需要删除大量的历史冗余数据,执行delete语句后,发现执行效率很慢,并且对当前数据库的IO有较大的消耗影响,此时查看数据库的资源占用情况:
undo表空间中常用的操作:
(1)查看undo表空间undotbs1的属性:

SQL> select b.tablespace_name,AUTOEXTENSIBLE,RETENTION from dba_tablespaces a,dba_data_files b where a.TABLESPACE_NAME=b.TABLESPACE_NAME and b.TABLESPACE_NAME='UNDOTBS1';

TABLESPACE_NAME AUT RETENTION
---------------------- --- ----------------
UNDOTBS1 NO NOGUARANTEE

(2)查看各个回退段的使用信息:

select a.name,b.extents,b.rssize,b.writes,b.xacts,b.wraps
from v$rollname a,v$rollstat b where a.usn=b.usn;

(3)确定哪些用户正在使用undo段:

SQL> select a.username,b.name,c.used_ublk from v$session a,v$rollname b,v$transaction c
         where a.saddr=c.ses_addr and b.usn=c.xidusn;
USERNAME NAME USED_UBLK
---------- ----------------------- ----------
NDMC _SYSSMU1_1255220753$ 1
NDMC _SYSSMU5_1255220754$ 1

(4)每秒生成的UNDO量,可以通过如下SQL得出:

SQL> SELECT (SUM(undoblks))/ SUM((end_time - begin_time) * 86400) FROM v$undostat;

(SUM(UNDOBLKS))/SUM((END_TIME-BEGIN_TIME)*86400)
--------------------------------------------------------------
          7.97590055

(5)当前undo表空间使用状态发现:

SQL> SELECT DISTINCT STATUS,SUM(BYTES),COUNT(*) FROM DBA_UNDO_EXTENTS GROUP BY STATUS;
STATUS SUM(BYTES) COUNT(*)
--------- ---------------- ----------
UNEXPIRED 3225157632 5667
EXPIRED 1063518208 1588
ACTIVE 1048576 1

(6)查看活动事务v$transaction

SQL> SELECT A.SID, A.USERNAME, B.XIDUSN, B.USED_UREC, B.USED_UBLK
     FROM V$SESSION A, V$TRANSACTION B WHERE A.SADDR=B.SES_ADDR;
       SID USERNAME XIDUSN USED_UREC USED_UBLK
       ---------- ------------ ---------- ---------- ----------
       407 NDMC 15 3 1
       
SQL> SELECT XID AS "txn_id", XIDUSN AS "undo_seg", USED_UBLK "used_undo_blocks",
     XIDSLOT AS "slot", XIDSQN AS "seq", STATUS AS "txn_status"
     FROM V$TRANSACTION;
     txn_id undo_seg used_undo_blocks slot seq txn_status
     ---------------- ---------- ---------------- ---------- --------- -------------
     14001600733A0C00 20 1 22 801395 ACTIVE

–查看未过期事务的占用情况:

 select BEGIN_TIME,
       END_TIME,
       MAXQUERYLEN,
       MAXQUERYSQLID,
       TUNED_UNDORETENTION
  from DBA_HIST_UNDOSTAT Order By begin_time Desc;

–死事务监控
由于执行进度太慢,并且对线上数据库造成一定的性能压力,于是人为KILL掉delete着过亿数据的事务,导致事务回滚一直在漫长进行着,UNDO表空间存在大量的活跃事务,查看UNDO表空间,该事务占用了大量UNDO块,此时处境比较尴尬,因为UNDO的回滚段正在读取,无法快速释放,尽管重启数据库,回滚还是依然需要进行的,只能等它慢慢处理完,因为这个是数据库的内部回滚操作!

SQL> select a.username,b.name,c.used_ublk from v$session a,v$rollname b,v$transaction c where a.saddr=c.ses_addr and b.usn=c.xidusn;
 
USERNAME NAME USED_UBLK
------------------------------ ------------------------------ ----------
RPT _SYSSMU4_1605577464$ 1845022
SQL> SELECT DISTINCT STATUS,SUM(BYTES),COUNT(*) FROM DBA_UNDO_EXTENTS GROUP BY STATUS;
 
STATUS SUM(BYTES) COUNT(*)
--------- ---------- ----------
UNEXPIRED 83165184 21
EXPIRED 12713984 44
ACTIVE 3421785292 917

–查看该死事务在回滚段中的位置

SQL> SELECT XID AS "txn_id",
  2 XIDUSN AS "undo_seg",
  3 USED_UBLK "used_undo_blocks",
  4 XIDSLOT AS "slot",
  5 XIDSQN AS "seq",
  6 STATUS AS "txn_status"
  7 FROM V$TRANSACTION;
 
txn_id undo_seg used_undo_blocks slot seq txn_status
---------------- ---------- ---------------- ---------- ---------- ----------------
04000300FB660000 4 1838729 3 26363 ACTIVE

–通过查看内部表可看到回滚剩余估计时间(需用SYS执行):

SQL> select ADDR, KTUXEUSN, KTUXESLT, KTUXESQN, KTUXESIZ
  2 from x$ktuxe where KTUXEUSN = 4 and KTUXESLT = 3;
 
ADDR KTUXEUSN KTUXESLT KTUXESQN KTUXESIZ
---------------- ---------- ---------- ---------- ----------
000000004E8419F0 4 3 26363 1836424 --剩余时间

–用下列过程可统计回滚剩余时间:

declare
  l_start number;
  l_end number;
begin
  select ktuxesiz
    into l_start
    from x$ktuxe
   where KTUXEUSN = 4
     and KTUXESLT = 3;
  dbms_lock.sleep(60); ---可以缩小这个时间,但是太小,可能会导致误差较大
  select ktuxesiz
    into l_end
    from x$ktuxe
   where KTUXEUSN = 4
     and KTUXESLT = 3;
  dbms_output.put_line('time est Day:' ||
                       round(l_end / (l_start - l_end) / 60 / 24, 2));
end;
 /
time est Day:.62
 
PL/SQL procedure successfully completed

晕! 62天,还要活吗?
所以回滚的代价是非常昂贵的,切勿以身试法!经过本地教训后,最稳妥的做法是分批delete操作,这样虽然麻烦一点,但不会造成UNDO严重损耗,并且不会造成巨大的回滚代价!