回滚段的学习
说实话至今没有用到过手动设置的回滚段,所以看这部分的内容有点像是屠龙之术,仅属于备用知识。貌似目前都是直接使用auto用undo表空间而很少有回滚段的操作,但是学习一下还是无妨。
一、回滚段的作用:
回滚段用于存放数据修改之前的值(也包括数据修改前的位置)。回滚段的头部包含正在使用的该回滚段事务的信息。一个事务只能使用一个回滚段来存放它的回滚信息,而一个回滚段可以存放多个事务的回滚信息。
回滚段用于对数据库修改时, 保存原有的数据, 以便稍后可以通过使用ROLLBACK来恢复到修改前的数据;另外, 回滚段可以为数据库中的所有进程提供读一致性. 因此, 回滚段设置的合理与否, 直接影响到数据库的性能, 在更新密集的OLTP应用中,更是如此.
其具体作用有以下几项:
1、事务回滚:
当事务修改表中数据的时候,该数据修改前的值(即前影像)会存放在回滚段中,当用户回滚事务(ROLLBACK)时,ORACLE将会利用回滚段中的数据前影像来将修改的数据恢复到原来的值。
2、事务恢复:
当事务正在处理的时候,例程失败,回滚段的信息保存在重做日志文件中,ORACLE将在下次打开数据库时利用回滚来恢复未提交的数据。
3、读一致性:
当一个会话正在修改数据时,其他的会话将看不到该会话未提交的修改。而且,当一个语句正在执行时,该语句将看不到从该语句开始执行后的未提交的修改(语句级读一致性)。当ORACLE执行SELECT语句时,ORACLE依照当前的系统改变号(SYSTEM CHANGE NUMBER-SCN)来保证任何前于当前SCN的未提交的改变不被该语句处理。可以想象:当一个长时间的查询正在执行时,若其他会话改变了该查询要查询的某个数据块,ORACLE将利用回滚段的数据前影像来构造一个读一致性视图。
事务级的读一致性:
ORACLE一般提供SQL语句级(SQL STATEMENT LEVEL)的读一致性,可以用以下语句来实现事务级的读一致性:
SET TRANSACTION READ ONLY;
或: SET TANNSACTION SERIALIZABLE;
以上两个语句都将在事务开始后提供读一致性。需要注意的是,使用第二个语句对数据库的并发性和性能将带来影响。
二、回滚段的类型:
1、系统回滚段:
当数据库创建后,将自动创建一个系统回滚段,它位于SYSTEM表空间,用于处理涉及系统的CataLog的事物(比如大多数的DDL)。
注意:不要把System回滚段放在其他的表空间中,并且应该永远保持ONLINE状态。
2、非系统回滚段:
拥有多个表空间的数据库至少应该有一个非系统回滚段,用于存放非系统表空间中对象的数据前影像。
非系统回滚段又分为私有回滚段和公有回滚段,私有回滚段应在参数文件的ROLLBACK_SEGMENTS参数中列出,以便例程启动时自动使其ONLINE(也可通过使用Alter Rollback Segment XXX Online来使用某一个回滚段)。公有回滚段一般在OPS(ORACLE并行服务器)中出现,将在例程启动时自动ONLINE。
建议将每个实例的Private回滚段放置到访问比较快的本地设备上。
3、DEFERED回滚段:
该回滚段在表空间离线(OFFLINE)时由系统自动创建,当表空间再次在线(ONLINE)时由系统自动删除,用于存放表空间离线时产生的回滚信息。
三、回滚段的使用:
(1) 创建回滚段
create
rollback
segment
rb01
tablespace
rbs1
storage
(
initial
100
K
next
100
K
minextents
20
maxextents
100
optimal
2000
K );
注意:
回滚段可以在创建时指明PRIVATE或PUBLIC,一旦创建将不能修改。
MINEXTENTS 必须大于等于2
PCTINCREASE必须是0
OPTIMAL如果要指定,必须大于等于回滚段的初始大小(由MINEXTENTS指定)
建议:
一般情况下,INITIAL=NEXT
设置OPTIMAL参数来节约空间的使用
不要设置MAXEXTENTS为UNLIMITED
回滚段应创建在一个特定的回滚段表空间内
(2) 更改ONLINE/OFFLINE状态
alter
rollback
segment
rb01
online
;
alter
rollback
segment
rb01
offline
;
当回滚段创建后,回滚段是离线的,不能被数据库使用,为了使回滚段被事务利用,必须将回滚段在线。
如果有事务正在使用该回滚段,运行offline命令后,回滚段的状态将是PENDING OFFLINE。事务结束后,状态将改为OFFLINE,可以通过V$ROLLSTAT查询回滚段的状态。
(3) 更改OPTIMAL参数
alter
rollback
segment
rb01
storage
(
maxextents
200
optimal
2048
K );
(4) 缩小回滚段
alter
rollback
segment
rb01
shrink
to
2048
K;
--
有
OPTIMAL
参数时
,
缩小到
OPTIMAL
值
alter
rollback
segment
rb01
shrink
;
--
没有
OPTIMAL
参数时
,
缩小到
MINEXTENTS
所对应的值
(5) 修改INITIAL/NEXT参数
--
修改
NEXT
时
,
总应该同时修改
INITIAL.
--INITIAL
参数无法直接修改
,
只能先
DROP,
然后再
CREATE.
drop
rollback
segment
rb01;
create
rollback
segment
rb01
tablespace
rbs1
storage
(
initial
100
K
next
100
K
minextents
20
maxextents
121
optimal
2000
K );
(6) 在事务中使用特定的回滚段
set
transaction
use
rollback
segment
rb01;
注意:
1、某个事务只能放在一个回滚段中,事务不可能分回滚段存放;一个回滚段可以存储多个事务。
2、几个事务可以写在回滚段的同一个区,一个事务也可以写在回滚段的不同区。
3、回滚段的block只能包含一个事务的信息。
4、当回滚段区的所有块用完而事务还需要更多的回滚空间时,回滚段的指针将移到下一个区。当最后一个区用完,指针将移到第一个区的前面。回滚段指针移到下一个区的前提是下一个区没有活动的事务,同时指针不能跨区。当下一个区正在使用时,事务将为回滚段分配一个新的区,这种分配称为回滚段的扩展(extend)。回滚段将一直扩展到该回滚段区的个数到达回滚段的参数MAXEXTENTS的值时为止。
例如:两个事务使用同一个回滚段,该回滚段有四个区:
1.事务在进行中,它们正在使用回滚段的第三个区;
2.当两个事务产生更多的回滚信息,它们将继续使用第三个区;
3.当第三个区满后,事务将写到第四个区,当事务开始写到一个新的区时,称为翻转(WRAP);
4.当第四个区用满时,如果第一个区是空闲或非活动(使用该区的所有事务完成而没有活动的事务)的,事务将接着使用第一个区。
(7) 常用的有关回滚段的系统数据字典
DBA_ROLLBACK_SEGS
--DBA_SEGMENTS
中的
ROLLBACK
类型
V$ROLLNAME
V$ROLLSTAT
V$TRANSACTION
--V$SESSION
回滚段的基本信息,
例:
SQL>SELECT segment_name,tablespace_name,owner,status FROM dba_rollback_segs;
回滚段的统计信息,
例:
SQL>SELECT n.name,s.extents,s.rssize,s.optsize,s.hwmsize,s.xacts,s.status
2 FROM v$rollname n,v$rollstat s
3 WHERE n.usn=s.usn;
回滚段的当前活动事务,例:
SQL>SELECT s.username,t.xidusn,t.ubafil,t.ubablk,t.used_ublk
2 FROM v$session s,v$transaction t
3 WHERE s.saddr=t.ses_addr;
USERNAME XIDUSN UBAFIL UBABLK USED_UBLK
------- -------- ----------- ----------- -----------
SYSTEM 2 2 7 1
SCOTT 1 2 163 1
2 rows selected.
三、回滚段的参数设置:
精确的回滚段的数量及大小的计算涉及很多方面:
1、应用的类型(OLTP/OLAP/BATCH)
2、同时进行的事物的数量
3、DML语句的类型
4、每个事物处理的数据量
5、……
回滚段使用的建议:
1、OLTP系统应使用小但较多的回滚段,每四个事务一个回滚段;每个回滚段不要超过十个事务。
2、OLAP系统/批处理系统应使用少量的大回滚段;每个事务一个回滚段。
3、OLTP/OLAP混合型系统中, 应专门设置一个或几个大的回滚段, 平时设置为OFFLINE, 使用时通过使用SET TRANSACTION USE ROLLBACK SEGMENT XXX来使用它。
这些回滚段应使用OPTIMAL参数,以便在不使用时,可以SHRINK到一个较小的尺寸;
3、在很难计算准确的数量、大小时,可用“偏大不偏小”的原则;
4、所有的回滚段的INITIAL/NEXT参数应设为相同, 只有建议3中提到的大回滚段例外;
5、不要将回滚段的MAXEXTENTS设为UNLIMITED, 回滚段所在表空间也不要设为AUTOEXTEND方式, 否则将会使得由于某个不正常的事务导致整个数据库处于失控状态。
四、回滚段的常见错误及解决方法:
(1) 回滚段空间不够
ORA-01562 - failed to extend rollback segment number string
回滚段空间不够的原因一般有以下几种情况:
A. 回滚段所在表空间剩余的空闲空间太小, 无法分配下一个EXTENT.
B. 回滚段扩展次数已经达到MAXEXTENTS限制
解决方法:
A. 扩大回滚段所在表空间
B. 设置较大的MAXEXTENTS参数
C. 为回滚段设置OPTIMAL参数
D. 用较大的EXTENT参数重新创建回滚段
E. 将导致ORA-1562错误的DML语句改为分段执行:
(2) ORA-01552 cannot use system rollback segment for non-system tablespace 'string'
原因: 没有可用的非系统回滚段. 分为以下情形:
A. 除了系统回滚段, 未创建其它回滚段
B. 只创建了PRIVATE回滚段, 但INITsid.ORA的ROLLBACK_SEGMENTS中未列出这些回滚段
C. 创建了PUBLIC回滚段, 但这些回滚段都处于OFFLINE状态
解决方法: 根据以上原因相应解决即可
(3) ORA_01555 snapshot too old: rollback segment number string with name "string" too small
原因可分为以下情形:
A. 回滚段太少/太小
数据库中有太多的事务修改数据并提交, 就会发生已提交事务曾使用的空间被重用, 从而造成一个延续时间长的查询所请求的数据已经不在回滚段中.
解决方法: 创建更多的回滚段, 为回滚段设置较大的EXTENT以及较大的MINEXTENTS
B. 回滚段被破坏
由于回滚段被破坏, 造成事务无法将修改前的内容(read-consistent snapshot) 放入回滚段, 也会产生ORA-01555错误.
解决方法: 将被破坏的回滚段OFFLINE, 删除重建.
C. FETCH ACROSS COMMIT
当一个进程打开一个CURSOR, 然后循环执行FETCH, UPDATE, COMMIT, 如果更新的表与FETCH的是同一个表, 就很可能发生ORA-01555错误.
解决方法:
a. 使用大的回滚段
b. 减少提交频率
以上两种方法只能减少该错误发生的可能, 不能完全避免. 如果要完全避免, 须从执行方法着手, 可以用以下两种方法:
c. 建立一个临时表, 存放要更新的表的查询列(如主键及相关的条件列), 从临时表FETCH, 更新原来的表.
d. 捕获ORA-01555错误, 关闭并重新打开CURSOR, 继续执行循环:
示例(示例程序的思路来源自ORACLE的UTLIP.SQL, 有兴趣的朋友可直接阅读该程序, 位置在RDBMS\ADMIN下, 程序很短, 容易读):
DECLARE
LAST_PK NUMBER := 0;
V_THEROWID ROWID;
CURSOR C1 IS
SELECT ROWID, PK, ... FROM SMPLE
WHERE PK > LAST_PK
AND othercondition
ORDER BY PK;
BEGIN
OPEN c_SOURCE;
LOOP
BEGIN
FETCH C1 INTO v_THEROWID, v_PK;
EXIT WHEN C1%NOTFOUND;
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -1555 THEN -- snapshot too old, re-execute fetch query
CLOSE C1;
OPEN c_SOURCE;
GOTO NEXTLOOP01555;
ELSE
RAISE;
END IF;
END;
LAST_PK := PK;
PROCESS,UPDATE AND COMMIT<>NULL;
END LOOP;
CLOSE C1;
END;
D. 其它原因:
* Delayed logging block cleanout是ORACLE用来提高写性能的一种机制: 当修改操作(INSERT/UPDATE/DELETE)发生时, ORACLE将原有的内容写入回滚段, 更新每个数据块的头部使其指向相应的回滚段, 当该操作被COMMIT时, ORACLE并不再重新访问一遍所有的数据块来确认所有的修改, 而只是更新位于回滚段头部的事务槽来指明该事务已被COMMIT, 这使得写操作可以很快结束从而提高了性能接下来的任何访问该操作所修改的数据的操作会使先前的写操作真正生效, 从而访问到新的值. Delayed logging block cleanout 虽然提高了性能, 但却可能导致ORA-01555. 这种情况下, 在OPEN/FETCH前对该表做全表扫描(保证所有的修改被确认)会有所帮助.
* 不适当的OPTIMAL参数: 太小的OPTIMAL参数会使回滚段很快被SHRINK, 造成后续读取操作访问时, 先前的内容已丢失. 仔细设计OPTIMAL参数, 不要让回滚段过于频繁的EXTEND/SHRINK有助于问题的解决.
* DB BLOCK BUFFER太小: 如果读一致性所请求的块的先前内容在缓冲区中, 那么就不用去访问回滚段. 而如果缓冲区太小, 使得先前版本的内容在CACHE中的可能性变小, 从而必须频繁的访问回滚段来获取先前的内容, 这将大大增大ORA-01555发生的可能.