管理可恢復空間
?
??? 學了半天都不知道這個內容到底講得是什么意思?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
;
?
?
?
?