管理可恢复空间分配
Oracle 数据库提供了一种机制,可在空间分配失败时暂停大型数据库操作的执行,并在之后恢复执行。因此,您可以采取纠正措施,而无需 Oracle 数据库服务器向用户返回错误。在错误条件修复后,被暂停的操作将自动恢复。此功能称为可恢复的空间分配,受影响的语句称为可恢复语句。
可恢复空间分配是如何工作的
可恢复空间分配的工作原理如下:
1.只有当执行语句的会话通过以下操作之一启用了可恢复空间分配功能时,语句才会以可恢复模式执行。
.当RESUMABLE_TIMEOUT初始化参数设置为非零值时,在执行语句之前,在会话中发出ALTER SESSION ENABLE RESUMABLE语句。
.ALTER SESSION ENABLE RESUMABLE TIMEOUT timeout_value语句在语句执行之前在会话中发出,且timeout_value是非零值。
2.当出现以下条件之一时,将挂起可恢复语句(这些条件会导致不可恢复语句发出相应的错误信号):
.超出空间状态
.达到的最大范围条件
.空间配额超出条件。
3.当可恢复语句的执行被挂起时,有一些机制可以执行用户提供的操作、记录错误和查询语句执行的状态。当一个可恢复语句被挂起时,将执行 以下操作:
.在警报日志中报告错误。
.系统发出恢复会话挂起警报。
.如果用户在后挂起系统事件上注册了触发,则执行用户触发。用户提供的PL/SQL过程可以使用DBMS_RESUMABLE包和DBA_或USER_RESUMABLE视图 来访问错误消息数据。
4.暂停语句会自动导致暂停事务。因此,所有事务资源都通过语句suspend和resume保存。
5.当错误条件解决后(例如,由于用户干预或其他查询释放的排序空间),暂停的语句自动恢复执行,可恢复的会话暂停警报被清除。
6.被挂起的语句可以使用DBMS_RESUMABLE.ABORT()过程强制抛出异常。DBA或发出语句的用户可以调用这个过程。
7.挂起超时时间间隔由初始化参数resume able_timeout或ALTER SESSION ENABLE resume timeout语句中的timeout值指定,与resume语句相关 联。如果错误条件没有在超时时间内解决,则暂停为超时时间的resume语句将被唤醒并向用户返回异常。
8.可恢复语句在执行过程中可以多次挂起和恢复。
哪些操作是可恢复的?
以下操作可以恢复:
.查询
用完临时空间(对于排序区域)的SELECT语句是可恢复执行的候选语句。当使用OCI时,调用ocstmtexecute()和OCIStmtFetch()是候选的。
.DML
INSERT、UPDATE 和 DELETE 语句都是候选对象。执行这些语句所使用的接口并不重要,可以是 OCI、PL/SQL 或其他接口。此外,从外部表中 INSERT INTO…SELECT 的操作也可以恢复。
.导入/导出
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
哪些错误是可以纠正的?
可纠正的错误有三类:
.超出空间状态
该操作不能为表空间中的表/索引/临时段/undo段/集群/LOB/表分区/索引分区获取更多的extent。例如,下列错误就属于这种类型:
ORA-01653 unable to extend table ... in tablespace ... ORA-01654 unable to extend index ... in tablespace ...
.达到的最大范围条件
表/索引/临时段/undo段/ cluster/LOB/表分区/索引分区中的extent数量等于该对象上定义的最大extent数量。例如,下列错误就属于这种类型 :
ORA-01631 max # extents ... reached in table ... ORA-01632 max # extents ... reached in index ...
.空间配额超出条件
用户在表空间中超过分配的空间配额。具体来说,下面的错误指出了这一点:
ORA-01536 space quote exceeded for tablespace string
可恢复空间分配和分布式操作
在分布式环境中,如果用户启用或禁用了可恢复空间分配,或者DBA修改了resume able_timeout初始化参数,那么本地实例就会受到影响。无法远程启用resume。
在分布式事务中,远程实例上的会话只有在远程实例已经在其站点上启用了resumeable时才被挂起。
并行执行和可恢复空间分配
在并行执行中,如果其中一个并行执行服务器进程遇到可纠正的错误,则该服务器进程暂停其执行。
其他并行执行的服务器进程将继续执行各自的任务,直到遇到错误或被暂停的服务器进程阻塞(直接或间接)为止。当可纠正的错误解决后,挂 起的进程恢复执行,并行操作继续执行。如果被挂起的操作终止,那么并行操作将中止,并向用户抛出错误。
不同的并行执行服务器进程可能会遇到一个或多个可纠正的错误。这可能导致并行地多次触发AFTER SUSPEND触发器。此外,如果一个并行执行 服务器进程遇到不可纠正的错误,而另一个并行执行服务器进程被挂起,则挂起的语句立即中止。
对于并行执行,每个并行执行协调器和服务器进程在DBA_或USER_RESUMABLE视图中都有自己的条目。
启用和禁用可恢复空间分配
通过运行SQL语句和设置某些初始化参数,可以启用和禁用可恢复空间分配。
关于启用和禁用可恢复空间分配
只有当语句在启用了恢复模式的会话中执行时,才可能进行可恢复空间分配。
当执行ALTER SESSION ENABLE RESUMABLEe语句时,启用会话的resume空间分配,并且将该会话的resumeable_timeout初始化参数设置为非零值 。当在系统级别设置resum_timeout初始化参数时,ALTER SESSION ENABLE RESUMABLE语句默认不指定超时值。当ALTER SESSION ENABLE RESUMABLE语句指定超时值时,它会覆盖系统默认值。
当执行ALTER SESSION ENABLE RESUMABLE语句时,在以下所有情况下都会禁用会话的可恢复空间分配:
.会话不会执行ALTER SESSION ENABLE RESUMABLE语句。
.会话执行ALTER SESSION DISABLE RESUMABLE语句。
.会话执行ALTER SESSION DISABLE RESUMABLE语句,超时值为0。
由于挂起的语句会占用一些系统资源,因此在允许用户启用可恢复空间分配和执行可恢复语句之前,必须授予用户RESUMABLE系统特权。
设置RESUMABLE_TIMEOUT初始化参数
你可以通过设置RESUMABLE_TIMEOUT初始化参数来指定一个默认的系统范围的超时时间。
例如,在初始化参数文件中的RESUMABLE_TIMEOUT参数设置为1小时:
RESUMABLE_TIMEOUT = 3600
如果这个参数设置为0,那么即使会话运行了没有超时值的ALTER SESSION ENABLE RESUMABLE语句也会禁用可恢复空间分配。
也可以使用ALTER SYSTEM SET语句在系统级别修改该参数的值。例如,下面的语句对所有运行了没有超时值ALTER SESSION ENABLE RESUMABLE语句的会话禁用resume空间分配:
SQL> ALTER SYSTEM SET RESUMABLE_TIMEOUT=0; System altered.
使用ALTER SESSION来启用和禁用可恢复空间分配
在会话中,用户可以使用ALTER SESSION SET语句设置RESUMABLE_TIMEOUT初始化参数,并启用可恢复空间分配、更改超时值或禁用可恢复模式。
用户可以使用以下SQL语句并使用系统默认设置的RESUMABLE_TIMEOUT值为会话启用恢复模式:
SQL> ALTER SESSION ENABLE RESUMABLE; Session altered.
要禁用恢复模式,用户发出以下语句:
SQL> ALTER SESSION DISABLE RESUMABLE; Session altered.
默认情况下,新会话的恢复模式是禁用的。用户还可以指定超时间隔,并提供用于标识可恢复语句的名称。
指定超时时间
当您启用恢复模式时,您可以设置一个超时时间,如果没有发生任何干预,则挂起的语句将出错。
下面的语句指定可恢复的事务将在3600秒后超时并出错:
SQL> ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600; Session altered.
TIMEOUT的值在被另一个ALTER SESSION ENABLE RESUMABLE语句修改之前一直有效,或者被其他方法修改,或者会话结束。如果没有设置 RESUMABLE_TIMEOUT初始化参数,那么使用ENABLE RESUMABLE TIMEOUT子句启用恢复模式时,默认的超时时间是7200秒。
命名可恢复语句
可恢复语句可以通过名称来标识。下面的语句为可恢复语句分配一个名称:
SQL> ALTER SESSION ENABLE RESUMABLE TIMEOUT 3600 NAME 'insert into table'; Session altered.
NAME值一直有效,直到被另一个ALTER SESSION ENABLE RESUMABLE语句修改,或者会话结束。NAME的默认值是“用户username(userid),会话 sessionid,实例instanceid”。
语句名用于标识DBA_RESUMABLE和USER_RESUMABLE视图中的resumable语句。
使用LOGON触发器设置默认的可恢复模式
除了设置RESUMABLE_TIMEOUT初始化参数之外,另一种设置默认恢复模式的方法是,你可以注册一个数据库级别的登录触发器来改变用户的会话 以启用恢复并设置一个超时间隔。
检测暂停语句
当一个可恢复的语句被挂起时,不会向客户端抛出错误。为了采取纠正措施,Oracle数据库提供了通知用户错误和提供有关情况的信息的替代方 法。
通知用户:AFTER SUSPEND系统事件和触发器
当可恢复语句遇到可纠正的错误时,系统内部会生成AFTER SUSPEND系统事件。用户可以在数据库和模式级别为该事件注册触发器。如果用户注 册一个触发器来处理此系统事件,则在SQL语句挂起之后执行该触发器。
在AFTER SUSPEND触发器中执行的SQL语句总是不可恢复的,并且总是自治的。在触发器内启动的事务使用SYSTEM回滚段。施加这些条件是为了克 服死锁并减少触发器遇到与语句相同的错误条件的机会。
用户可以使用USER_RESUMABLE或DBA_RESUMABLE视图,DBMS_RESUMABLE。SPACE_ERROR_INFO函数,在触发器中获取有关可恢复语句的信息。
触发器还可以调用DBMS_RESUMABLE包来终止挂起的语句并修改恢复超时值。在下面的例子中,默认系统超时时间是通过创建一个系统层面的 AFTER SUSPEND触发器调用DBMS_RESUMABLE将超时时间设置为3小时:
SQL> CREATE OR REPLACE TRIGGER resumable_default_timeout 2 AFTER SUSPEND 3 ON DATABASE 4 BEGIN 5 DBMS_RESUMABLE.SET_TIMEOUT(10800); 6 END; 7 / Trigger created.
可恢复的空间分配示例:注册一个AFTER SUSPEND触发器
一个示例说明了如何在挂起触发器后创建一个系统范围内的系统,并在数据库级别将其注册到SYS用户下。
当一个可恢复的语句在任何会话中被挂起时,这个触发器可以有两种效果:
.如果一个undo段已经达到了它的空间限制,那么一条消息将被发送给DBA,语句将被终止。
.如果出现其他可恢复的错误,则超时时间重置为8小时。
下面是这个例子的语句:
SQL> CREATE OR REPLACE NONEDITIONABLE TRIGGER resumable_default
2 AFTER SUSPEND
3 ON DATABASE
4 DECLARE
5 /* declare transaction in this trigger is autonomous */
6 /* this is not required because transactions within a trigger
7 are always autonomous */
8 PRAGMA AUTONOMOUS_TRANSACTION;
9 cur_sid NUMBER;
10 cur_inst NUMBER;
11 errno NUMBER;
12 err_type VARCHAR2(2000);
13 object_owner VARCHAR2(2000);
14 object_type VARCHAR2(2000);
15 table_space_name VARCHAR2(2000);
16 object_name VARCHAR2(2000);
17 sub_object_name VARCHAR2(2000);
18 error_txt VARCHAR2(2000);
19 msg_body VARCHAR2(2000);
20 ret_value BOOLEAN;
21 mail_conn UTL_SMTP.CONNECTION;
22 BEGIN
23 -- Get session ID
24 SELECT DISTINCT(SID) INTO cur_SID FROM V$MYSTAT;
25 -- Get instance number
26 cur_inst := userenv('instance');
27 -- Get space error information
28 ret_value :=
29 DBMS_RESUMABLE.SPACE_ERROR_INFO(err_type,object_type,object_owner,
30 table_space_name,object_name, sub_object_name);
31 /*
32 -- If the error is related to undo segments, log error, send email
33 -- to DBA, and abort the statement. Otherwise, set timeout to 8 hours.
34 --
35 -- sys.rbs_error is a table which is to be
36 -- created by a DBA manually and defined as
37 -- (sql_text VARCHAR2(1000), error_msg VARCHAR2(4000),
38 -- suspend_time DATE)
39 */
40 IF OBJECT_TYPE = 'UNDO SEGMENT' THEN
41 /* LOG ERROR */
42 INSERT INTO sys.rbs_error (
43 SELECT SQL_TEXT, ERROR_MSG, SUSPEND_TIME
44 FROM DBA_RESUMABLE
45 WHERE SESSION_ID = cur_sid AND INSTANCE_ID = cur_inst
46 );
47 SELECT ERROR_MSG INTO error_txt FROM DBA_RESUMABLE
48 WHERE SESSION_ID = cur_sid and INSTANCE_ID = cur_inst;
49 -- Send email to receipient through UTL_SMTP package
50 msg_body:='Subject: Space Error Occurred Space limit reached for undo segment ' || object_name || 'on ' || TO_CHAR (SYSDATE, 'Month dd, YYYY, HH:MIam') ||'. Error message was ' || error_txt;
51 mail_conn := UTL_SMTP.OPEN_CONNECTION('localhost', 25);
52 UTL_SMTP.HELO(mail_conn, 'localhost');
53 UTL_SMTP.MAIL(mail_conn, 'sender@localhost');
54 UTL_SMTP.RCPT(mail_conn, 'recipient@localhost');
55 UTL_SMTP.DATA(mail_conn, msg_body);
56 UTL_SMTP.QUIT(mail_conn);
57 -- Abort the statement
58 DBMS_RESUMABLE.ABORT(cur_sid);
59 ELSE
60 -- Set timeout to 8 hours
61 DBMS_RESUMABLE.SET_TIMEOUT(28800);
62 END IF;
63 /* commit autonomous transaction */
64 COMMIT;
65 END;
66 /
Trigger created.