管理可恢复空间
学了半天都不知道这个内容到底讲得是什么意思?Oracle有可恢复空间这个概念吗?实在是不理解……
一、可恢复空间分配的概述
1、可恢复语句如何工作:
① 客户使用ALTER SESSION语句明确启用可恢复时才可以执行恢复
② 以下情况下,可恢复语句被暂停:
* 没有空间条件
* 达到最大盘区条件
* 超过空间限额条件
③ 可恢复语句执行被暂停期间,采用以下动作:
* 修改日志中报告错误
* 若在AFTER SUSPEND系统事件上注册触发器,则触发器执行
(使用DBMS_RESUMABLE包和DBA_RESUMABLE视图访问错误信息数据)
④ 暂停一个语句自动导致暂停该事务。(暂停到恢复期间所有事务资源被保持)
⑤ 出错条件消失时,暂停语句自动恢复执行
⑥ 使用DBMS_RESUMABLE.ABORT()过程,可强制暂停语句发出异常
⑦ 暂停超过时间间隔与可恢复语句相关联(例如超过2小时的可恢复语句被唤醒并报错)
⑧ 可恢复语句在执行期间可被多次暂停和恢复。
注:可恢复方式不支持远程操作。
2、可恢复的操作
① 查询:
用到临时空间(排序区)的SELECT语句是可恢复的。
当使用OCI时OCIStmtExecute()和OCIStmtFetch()调用是可恢复的。
② DML:
包括INSERT、UPDATE、DELETE,以及来自外部表的INSERT ONTO ... SELECT
与执行它们的接口无关,可以是OCI、JSQL、PL/SQL或其他接口
③ 导入/导出
SQL*Loader的命令行出现可更改错误之后是可恢复的
④ DDL:以下语句是可恢复的:
① CREATE TABLE ... AS SELECT
② CREATE INDEX
③ ALTER INDEX ... REBUILD
④ ALTER TABLE ... MOVE PARTITION
⑤ ALTER TABLE ... SPLIT PARTITION
⑥ ALTER INDEX ... REBUILD PARTITION
⑦ ALTER INDEX ... SPLIT PARTITION
⑧ CREATE MATERIALIZED VIEW
⑨ CREATE MATERIALIZED VIEW LOG
3、哪些错误是可改正的
① 没有空间条件
② 达到最大盘区条件
③ 超过空间限额条件
4、字典管理的表空间可恢复空间分配的限制
① CREATE TABLE 或 CREATE INDEX这样的DDL操作执行时,使用了MAXEXTENTS参数,会导致空间用完的情况。此时操作不会被暂停,而是被放弃。因为在初期创建的时候无法进行修改。而如果是DML操作增加或修改了MAXEXTENTS参数,则会被暂停并在以后恢复。注意可以使用MAXEXTENTS UNLIMITED或使用本地管理的表空间来克服。
② 回滚段位于字典管理的表空间中时,对回滚段的空间分配是不可恢复的。但是对于用户对象的空间按分配仍然可恢复。要克服这种限制,建议使用自动撤销管理或将回滚段放置在本地管理的表空间中。
二、启用和禁用可恢复空间分配
1、语句格式:
ALTER SESSION ENABLE RESUMABLE; --启用
ALTER SESSION DISABLE RESUMABLE; --禁用
2、指定超时间隔
超时间隔表示超过该间隔时间如果没有采取干预,暂停语句会出错。
① 一种方法是使用SQL语句来进行修改:
ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600; --默认7200秒
② 另一种方法可以用触发器来设置,如:
CREATE OR REPLACE TRIGGER resumable_default_timeout
AFTER SUSPEND
ON DATABASE
BEGIN
DBMS_RESUMABLE.SET_TIMEOUT(3600);
END;
3、可恢复语句命名
ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600 NAME 'insert into table';
NAME的默认值是:User USERNAME(USERID), Session SESSIONID, Instance INSTANCEID
NAME用于在DBA_RESUMABLE和USER_RESUMABLE视图中标识该可恢复语句
三、检测暂停的语句
因为可恢复语句被暂停时,客户端并不会报错,为了采取纠正动作,需要检测暂停语句。
1、AFTER SUSPEND系统事件和触发器
在AFTER SUSPEND触发器中,可以使用USER_RESUMABLE或DBA_RESUMABLE视图,或者DBMS_RESUMABLE.SPACE_ERROR_INFO函数来获取关于可恢复语句的信息,以及用来放弃暂停的语句或调节可恢复超时间隔的值。
2、在视图中查看
DBA_RESUMABLE:包含当前正在执行或被暂停的可恢复语句的行。
V$SESSION_WAIT:语句被暂停即进入等待状态,选择EVENT值为“susprended on space error”的行。
3、DBMS_RESUMABLE包介绍
① ABORT(sessionID):
放弃一个暂停的可恢复语句。sessionID是该语句在其执行的会话的标识。对于并行的DML/DDL,则取任何一个sessionID。
可以在AFTER SUSPEND触发器内调用,也可以在触发器外调用。
② GET_SESSION_TIME3OUT(sessionID):
为使用sessionID的会话返回可恢复语句的当前超时间隔,单位秒。会话不存在时返回-1。
③ SET_SESSION_TIMEOUT(sessionID,timeout):
为sessionID设置超时间隔,会话不存在时则不做任何动作。
④ GET_TIMEOUT():
返回当前会话的可恢复语句当前超时间隔值。
⑤ SET_TIMEOUT(timeout):
为当前会话的可恢复语句设置一个超时间隔。
四、可恢复空间分配的例子
建立一个触发器,其有以下两个作用:
1、如果回滚段达到它的空间限额,那么一条消息发给DBA且该语句被放弃
2、如果任何其他的可改正错误发生,超时间隔被重置为8小时
CREATE
OR
REPLACE
TRIGGER
resumable_default
AFTER
SUSPEND
ON
DATABASE
DECLARE
/* declare transaction in this trigger is autonomous */
/* this is not required because transactions within a trigger are always autonomous */
PRAGMA
AUTONOMOUS_TRANSACTION
;
cur_sid
NUMBER
;
cur_inst
NUMBER
;
errno
NUMBER
;
err_type
VARCHAR2
;
object_owner
VARCHAR2
;
object_type
VARCHAR2
;
table_space
VARCHAR2
;
sub_object_name
VARCHAR2
;
error_txt
VARCHAR2
;
msg_body
VARCHAR2
;
ret_value
BOOLEAN
;
mail_conn UTL_SMTP.CONNECTION;
BEGIN
-- Get session ID
SELECT
DISTINCT
(SID)
INTO
cur_SID
FROM
V$MYSTAT;
-- Get instance number
ret_value := DBMS_RESUMABLE.SPACE_ERROR_INFO(err_type,
object_type,
object_owner,
table_space_name,
object_name,
sub_object_name);
/*
-- If the error is related to rollback segment, log error, send email
-- to DBA, and abort the segment. Otherwise, set timeout to a8 hours.
--
-- sys.rbs_error is created by DBA manually and defined as
-- sql_text VARCHAR2(1000), error_msg VARCHAR2(4000),
-- suspend_time DATE
*/
IF
OBJECT_TYPE =
'ROLLBACK SEGMENT'
THEN
/* LOG ERROR */
INSERT
INTO
sys.rbs_error
(
SELECT
SQL_TEXT, ERROR_MSG, SUSPEND_TIME
FROM
DBMS_RESUMABLE
WHERE
SESSION_ID = cur_sid
AND
INSTANCE_ID = cur_inst);
SELECT
ERROR_MSG
INTO
error_txt
FROM
DBMS_RESUMABLE
where
SESSION_ID = cur_sid
AND
INSRANCE_ID = cur_inst;
-- Send email to receipient via UTL_SMTP package
msg_body :=
'Subject: Space Error Occurred
Space limit reached for rollback segment'
|| object_name ||
'on'
||
TO_CHAR(
SYSDATE
,
'Month dd, YYYY, HH:MIam'
) ||
'. Error message was'
|| error_txt;
mail_conn := UTL_SMTP.OPEN_CONNECTION(
'localhost'
,
25
);
UTL_SMTP.HELO(mail_conn,
'localhost'
);
UTL_SMTP.MAIL(mail_conn,
'sender@localhost'
);
UTL_SMTP.RCPT(mail_conn,
'recipient@localhost'
);
UTL_SMTP.DATA(mail_conn, msg_body);
UTL_SMTP.QUIT(mail_conn);
-- Abort the segment
DBMS_RESUMABLE.ABORT(cur_sid);
ELSE
-- Set timeout to 8 hours
DBMS_RESUMABLE.SET_TIMEOUT(
28800
);
END
IF
;
/* commit autonomous transaction */
COMMIT
;
END
;