Oracle UNDOTBS%_TABLESPACE认识
Redo中只会记录少量信息,这些信息足以重演事务;同样Undo中也只记录精简信息,这些信息足以撤销事务。具体来说:
1 对于INSERT操作,回滚段只需要记录插入记录的ROWID,如果回退,那么只需将该记录根据ROWID删除即可;
2 对于UPDATE操作,回滚段只需要记录被更新字段的旧值即可(前镜像),回退时通过旧值覆盖新值即可完成回滚;
3 对于DELETE操作,Oracle则必须记录整行的数据,在回滚时,Oracle通过一个反向操作恢复删除的数据。
总结一下:对于相同数据量的数据操作,通常INSERT产生最少的Undo,UPDATE产生的Undo居中,而DELETE操作产生的Undo最多。
所以,当一个大的DELETE操作失败或者回滚,总是需要很长的时间,并且会有大量的Redo生成。
所以通常在进行大规模数据删除操作时,推荐通过分批删除分次提交,以减少对于回滚段的占用和冲击。
Undo信息存储在Undo段中,Undo段又存储在Undo表空间中。Undo表空间仅用于Undo段(在Undo表空间中不能创建其它段类型,例如表、索引等),只能与单个实例相关联。
在任意指定时间,一个给定的实例只能有一个表空间是当前可写Undo表空间。Undo表空间是永久的、本地管理的表空间(具有自动区分配),它们由数据库自动进行管理。
Oracle Undo段中区3种状态(DBA_UNDO_EXTENTS的STATUS列):ACTIVE、EXPIRED和UNEXPIRED:
1 ACTIVE即未提交的Undo信息(活动):表示事物还在活动,该值对应的Undo段的DBA_ROLLBACK_SEGS.STATUS一定是ONLINE状态,一旦没有活动的事务在使用Undo段,那么对应的Undo段就变成OFFLINE状态。ACTIVE状态的Undo区不会被覆盖。
2 EXPIRED即过期的Undo信息(过期):表示事务已经提交且超过了UNDO_RETENTION指定时间,该状态可以被覆盖使用。
3 UNEXPIRED即提交的Undo信息(未过期):表示事务已经提交但是还没有超过UNDO_RETENTION指定时间,该状态可以被覆盖使用。
--delete模板
DECLARE
COUNTS INT;
TYPE RIDARRAY IS TABLE OF ROWID INDEX BY PLS_INTEGER;
V_ROWID RIDARRAY;
CURSOR IB_DELETE IS SELECT ROWID FROM CQ_TEST_OBJECTS_TABLE ORDER BY ROWID;
BEGIN
COUNTS := 0;
OPEN IB_DELETE;
LOOP
FETCH IB_DELETE BULK COLLECT INTO V_ROWID LIMIT 5000; --每次处理5000行
EXIT WHEN V_ROWID.COUNT=0;
FORALL I IN V_ROWID.FIRST .. V_ROWID.LAST
DELETE FROM CQ_TEST_OBJECTS_TABLE WHERE ROWID = V_ROWID(I); --根据实际修改删除数据的条件
COMMIT;
COUNTS := COUNTS+1;
DBMS_OUTPUT.put_line(COUNTS||' Commit!');
END LOOP;
CLOSE IB_DELETE;
END;
/
--大表排重 (使用时出现Oracle undo表空间爆满)
DECLARE
COUNTS INT;
TYPE RIDARRAY IS TABLE OF ROWID INDEX BY PLS_INTEGER;
V_ROWID RIDARRAY;
--整理需要删除的数据的ROWID,根据条件修改
CURSOR IB_DELETE IS SELECT ROWID FROM dwr_lot_defect_his_m PARTITION(PART_201908) T2 WHERE NOT EXISTS (SELECT 1
FROM (SELECT MIN(ROWID) AS RID FROM dwr_lot_defect_his_m PARTITION(PART_201908) T1 GROUP BY T1.history_seq) T3 WHERE T3.RID = T2.ROWID) --ORDER BY 1
;
BEGIN
COUNTS := 0;
OPEN IB_DELETE;
LOOP
FETCH IB_DELETE BULK COLLECT
INTO V_ROWID LIMIT 1000; --每次处理1000行
EXIT WHEN V_ROWID.COUNT=0;
FORALL I IN V_ROWID.FIRST .. V_ROWID.LAST
DELETE FROM TEST_OBJECTS_TABLE_CQ WHERE ROWID = V_ROWID(I);
COMMIT;
COUNTS := COUNTS+1;
DBMS_OUTPUT.PUT_LINE(COUNTS||' Commit!');
END LOOP;
CLOSE IB_DELETE;
END;
/
查询 Undo表空间使用情况
--UNDOTBS% TABLESPACE使用情况
SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
D.TOT_GROOTTE_MB "表空间大小(M)",
D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100,2),'990.99') || '%' "使用比",
F.TOTAL_BYTES "空闲空间(M)",
F.MAX_BYTES "最大块(M)"
FROM
(SELECT TABLESPACE_NAME,ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES FROM SYS.DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) F,
(SELECT DD.TABLESPACE_NAME,ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB FROM SYS.DBA_DATA_FILES DD GROUP BY DD.TABLESPACE_NAME) D
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
AND D.TABLESPACE_NAME LIKE 'UNDOTBS%'
ORDER BY 1;
=======================================================================================
--查看数据表空间大小
SELECT
FILE_NAME, TABLESPACE_NAME, AUTOEXTENSIBLE, INCREMENT_BY,
BYTES/1024/1024/1024 "DISK_SIZE(G)", MAXBYTES/1024/1024/1024 "MAX_SIZE(G)"
FROM
DBA_DATA_FILES
WHERE
TABLESPACE_NAME IN ('UNDOTBS1','UNDOTBS2');
=======================================================================================
--有关Undo表空间常用的几个视图如下所示:
SELECT OWNER,SEGMENT_NAME,BYTES/1024/1024 MB FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='UNDOTBS1';
SELECT * FROM DBA_ROLLBACK_SEGS;
SELECT * FROM V$ROLLNAME;
SELECT * FROM DBA_UNDO_EXTENTS;
SELECT TABLESPACE_NAME, STATUS, SUM(BYTES) / 1024 / 1024 "Bytes(M)"
FROM DBA_UNDO_EXTENTS
GROUP BY TABLESPACE_NAME, STATUS;
SELECT R.STATUS "Status",
R.SEGMENT_NAME "Name",
R.TABLESPACE_NAME "Tablespace",
S.EXTENTS "Extents",
TO_CHAR((S.BYTES / 1024 / 1024), '99999990.000') "Size"
FROM SYS.DBA_ROLLBACK_SEGS R,
SYS.DBA_SEGMENTS S
WHERE R.SEGMENT_NAME = S.SEGMENT_NAME
AND S.SEGMENT_TYPE IN ('ROLLBACK', 'TYPE2 UNDO')
ORDER BY 5 DESC;
SELECT R.NAME 回滚段名,
S.SID SID,
S.SERIAL# SERIAL,
S.USERNAME 用户名,
S.MACHINE 机器名,
T.START_TIME 开始时间,
T.STATUS 状态,
T.USED_UBLK 撤消块,
USED_UREC 撤消记录,
T.CR_GET 一致性取,
T.CR_CHANGE 一致性变化,
T.LOG_IO "逻辑I/O",
T.PHY_IO "物理I/O",
T.NOUNDO NOUNDO,
G.EXTENTS EXTENTS,
SUBSTR(S.PROGRAM, 1, 100) 操作程序
FROM V$SESSION S,
V$TRANSACTION T,
V$ROLLNAME R,
V$ROLLSTAT G
WHERE T.ADDR = S.TADDR
AND T.XIDUSN = R.USN
AND R.USN = G.USN
ORDER BY T.USED_UBLK DESC;
Oracle undo表空间爆满的处理方法
--Oracle undo表空间爆满的解决步骤:
--1. 启动SQLPLUS,并用sys登陆到数据库
#su - oracle
$>sqlplus / as sysdba ;
--2. 查找数据库的UNDO表空间名,确定当前例程正在使用的UNDO表空间:
SQL> Show parameter undo_tablespace;
/*
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_tablespace string UNDOTBS1
*/
--3. 确认UNDO表空间;
SQL> select * from v$tablespace where name like 'UNDOTBS%';
/*
TS# NAME INCLUDED_IN_DATABASE_BACKUP BIGFILE FLASHBACK_ON ENCRYPT_IN_BACKUP CON_ID
---------- ------------------------------ --------------------------- ------- ------------ ----------------- ----------
2 UNDOTBS1 YES NO YES 0
5 UNDOTBS2 YES NO YES 0
*/
--4. 检查数据库UNDO表空间占用空间情况以及数据文件存放位置;
SQL>select file_name,bytes/1024/1024 from dba_data_files where tablespace_name like 'UNDOTBS%';
/*
FILE_NAME BYTES/1024/1024
-------------------------------------------------------------------------------- ---------------
+DG_DATA/EDWDB/DATAFILE/undotbs1.267.963681681 32767.984375
+DG_DATA/EDWDB/DATAFILE/undotbs1.482.1018520415 30720
+DG_DATA/EDWDB/DATAFILE/undotbs2.265.963682089 32725
+DG_DATA/EDWDB/DATAFILE/undotbs2.481.1018520367 30720
*/
--5. 查看回滚段的使用情况,哪个用户正在使用回滚段的资源,如果有用户最好更换时间(特别是生产环境)。
SQL> select s.username, u.name from v$transaction t,v$rollstat r, v$rollname u,v$session s where s.taddr=t.addr and t.xidusn=r.usn and r.usn=u.usn order by s.username;
/*
*/
--6. 检查UNDO Segment状态; 查看有多少个回滚对象
SQL> select usn,xacts,rssize/1024/1024/1024,hwmsize/1024/1024/1024,shrinks from v$rollstat order by rssize;
SQL> select t.segment_name,t.tablespace_name,t.segment_id,t.status from dba_rollback_segs t where t.tablespace_name='UNDOTBS1' ORDER BY t.status DESC;
/*
USN XACTS RSSIZE/1024/1024/1024 HWMSIZE/1024/1024/1024 SHRINKS
1 0 0 0.000358582 0.000358582 0
2 14 0 0.796791077 0.796791077 735
3 44 1 0.00920867919921875 3.99295806884766 996
这还原表空间中还存在3个回滚的对象。 */
--7. 创建新的UNDO表空间,并设置自动扩展参数;
SQL> create undo tablespace undotbs2 datafile '/opt/oracle/oradata/ge01/UNDOTBS2.dbf' size 100m reuse autoextend on next 50m maxsize 5000m;
Tablespace created.
--8. 切换UNDO表空间为新的UNDO表空间 , 动态更改spfile配置文件;
SQL> alter system set undo_tablespace=undotbs2 scope=both;
System altered.
--9.验证当前数据库的 UNDO表空间
SQL> show parameter undo;
/*
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
temp_undo_enabled boolean FALSE
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS1
*/
--10. 等待原UNDO表空间所有UNDO SEGMENT OFFLINE;
SQL> select usn,xacts,status,rssize/1024/1024,hwmsize/1024/1024, shrinks from v$rollstat order by rssize;
SQL> select t.segment_name,t.tablespace_name,t.segment_id,t.status from dba_rollback_segs t;
/*
SEGMENT_NAME TABLESPACE_NAME SEGMENT_ID STATUS
1 SYSTEM SYSTEM 0 ONLINE
2 _SYSSMU1$ UNDOTBS1 1 OFFLINE
3 _SYSSMU2$ UNDOTBS1 2 OFFLINE
4 _SYSSMU47$ UNDOTBS1 47 OFFLINE
上面对应的UNDOTBS1还原表空间所对应的回滚段均为OFFLINE
*/
--11.到$ORACLE_HOME/dbs/init$ORACLE_SID.ora如下内容是否发生变更:
#cat $ORACLE_HOME/dbs/initddptest.ora
/*
/……
*.undo_management=’AUTO’
*.undo_retention=10800
*.undo_tablespace=’UNDOTBS2’
……
*/
--如果没有发生变更请执行如下语句:
SQL> create pfile from spfile;
File created.
--12. 删除原有的UNDO表空间;
SQL> drop tablespace undotbs1 including contents;
--最后需要在重启数据库或者重启计算机后到存储数据文件的路径下删除数据文件(为什么要手动删除呢:以上步骤只是删除了ORACLE中undo表空间的逻辑关系,即删除了数据文件在数据字典中的关联,不会自动删除项关联的数据文件)。
--13.重启数据库
SQL> startup force
ORACLE instance started.
drop tablespace undotbs1 including contents and datafiles;