(12)空间不足,留个亡羊补牢的机会给自己。

      在日常项目维护中 DBA会经常主动地去检查表空间是否够用,但数据库还是能搞出空间问题。我在后面会列一些常 
见的可能让你的表空间脱出掌握的操作。而我今天说的这个特性可好了,它可以让你在出现空间问题时有足够的时间
去解决它,让业务继续。不是表空间的自动扩展(autoextent),它有它的问题列情况时有说明.
列一些可以会出现空间问题的情况:
1. 一条数据量很大的SELECT,把临时表空间给用尽了。
2. 大批量的DELETE,让撤销表空间空间不足。
3.临时或定时的sqlldr,因对数据量估计不足,导致表空间用完。
4.采用祼设备的表空间,空间不足。
5.物理存储上的空间不足了,表空间自动扩展失败。
6. 操作系统文件的4GB限制,不过这个现在应当很少见了。
7. 表空间分配给表的空间用完了。
8. ....

       列的这些情况中,有些通过细心的检查是可以规避的,但有些确实是容易忽略或规避不了的。而如果发生了这种
现象,后果就不说了,为给了DBA们找条生路,Oracle提供了一个叫 可恢复的空间分配(RESUMABLE)特性它可以
在发生空间不足时,让正在执行的操作挂起,只要在设定的时间内(默认为2小时)解决空间问题后,操作如常继续。
    
    设置步骤:
      1. 在系统级别启用它,让所有会话都可以享受这个功能。 (仅11g及以上可用)   
-- 设置为 7200 秒即2小时 ,动态参数,无需库重启。
   -- 如把值设为 0 ,即禁用些特性
SQL> alter system set resumable_timeout = 7200; 
系统已更改。
SQL> show parameter resumable_timeout
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
resumable_timeout integer 7200

     2. 在session级别启用它
 2.1 授权(dba用户自带就有)  
grant resumable to xcl;
2.2 在 session 中启用它 
 --启用
  alter session enable resumable timeout 10000;
 --禁用 
  alter session disable resumable;

3. 当出现问题时,可以在dba_resumable或用户的user_resumable中查到启用了这个功能的会话的状态及SQL语句。
  即哪些会话及SQL被挂起了。 挂起时 status值为SUSPENDED.  正常后为 NORMAL.
SELECT user_id,session_id,status,name,sql_text FROM dba_resumable;
SELECT session_id,status,name,sql_text FROM user_resumable;
  --查看参数 
 show parameter resumable_timeout
 
如何测试?
1.新建一个空间很小的测试表空间,并将autoextend 关掉.
create table testrs_data datafile '路径' size 1m autoextend off;
2. 新增一个用户,并使用这个表空间,并授resumable权限    
create user testrs identifyed by testrs ;
grant connect to testrs;
grant resource to testrs;
grant resumable to testrs;
3. 在测试用户下新增一个表,并不停地向里面插入数据,直到把空间用完为止。
     --简单点可以建个带blob类型的表,连接插入几个几百KB的文件就行了。在这就不举例了。

4. 启用可恢复表空间分配    
 --可挂起1个小时
   alter session enable resumable timeout 3600; 

5. 再去执行插入语句,应当会报错,不过这一次应当可以在 user_resumable 中看到它了,并且adrci中也能查到这个错误 。
SELECT user_id,session_id,status,name,sql_text FROM dba_resumable;
或
SELECT session_id,status,name,sql_text FROM user_resumable;

6.把表空间扩下容  
alter tablespace testrs_data  add datafile '路径' size 1m;

7. 再去执行插入语句,这次应当顺利通过, 视图中的status应当变为了NORMAL.

       除了上面的方式,Oracle还提供了一个包dbms_resumable作为辅助,在工具下,可以去包定义里面的函数相应应当都懂。
不过手工在session真处理的方式,在实际中并不实用,顶多用来做做测试,
真正要使用,需要利用数据库trigger来实现看下面:       

1. 在schema 级别,让用户在登录时就设置
  --在schema 级别,让用户在登录时就设置
create or replace trigger trg_db_logon_sets
  after logon on demo.schema
declare
  -- local variables here
begin
  --前提是用户有resumable权限
  --启用可恢复表空间分配
  execute immediate 'alter session enabled resumable timeout 7200';
end trg_db_logon_sets;

2.  在数据库 after suspend事件中加个trigger,一有挂起发生就发邮件
create or replace trigger trg_db_resumable_notify
  after suspend on database
declare
  -- local variables here
  v_dba_resumable dba_resumable%rowtype;
  v_sessionsid NUMBER;
  v_inst NUMBER;
  v_err_type VARCHAR2(255);
  v_object_owner VARCHAR2(80);
  v_object_type VARCHAR2(80);
  v_table_space_name VARCHAR2(80);
  v_object_name VARCHAR2(80);
  v_sub_object_name VARCHAR2(80);
  v_ret BOOLEAN;
 
begin
   --得到当前session ID
   SELECT DISTINCT(SID) INTO v_sessionsid FROM V$MYSTAT;
     
    --实例序号
  v_inst := userenv('instance');
 
   --得到挂起空间错误信息,可以用来做些区分处理,暂时不用
   -- if(v_object_owner == 'DEMO') dbms_resumable.set_timeout(7200 * 2); end;
   -- if(v_object_type == 'UNDO SEGMENT')
  v_ret := DBMS_RESUMABLE.SPACE_ERROR_INFO(v_err_type,v_object_type,v_object_owner,
                                v_table_space_name,v_object_name, v_sub_object_name);
                               
    SELECT * INTO v_dba_resumable
            FROM dba_resumable
           WHERE session_id = v_sessionsid
             AND instance_id = v_inst
             AND status = 'SUSPENDED'
             AND rownum < 2;

   --发送邮件
  --有些数据库可能报找不到utl_mail包的错误,这个包是要另外新建的。
   utl_mail.send(sender=>'xcl_168@aliyun.com',
           recipients=>'xxxx@aliyun.com',
           subject=>'oracle resumable!!!',
           cc=>'xxxx@aliyun.com,xxxx@aliyun.com',
           bcc=>'xxxx@aliyun.com,xxxx@aliyun.com',
           message=>'inst:'||v_inst||chr(13)||
                   ' session sid:'||v_sessionsid||chr(13)||
                   ' object_type:'||v_object_type||chr(13)||
                   ' object_owner:'||v_object_owner||chr(13)||
                   ' table_space_name:'||v_table_space_name||chr(13)||
                   ' object_name:'||v_object_name||chr(13)||
                   ' sub_object_name:'||v_sub_object_name||chr(13)||
                   ' view error_msg:'||v_dba_resumable.error_msg );

end trg_db_logon_sets;
    这种非表级的Trigger要小心,代码检查通过,但执行有问题就会报  ORA-00604: 递归 SQL 级别 1 出现错误 ,所以写好后,最后 disconnect;后再conn 用户一下看正常不.

至此,就真正让这个特性落地,可以实用了。

MAIL: xcl_168@aliyun.com



以下是一个简单的实现这个功能的Android应用程序: 1. 在activity_main.xml文件中添加一个TextView和一个Button控件: ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.randomword.MainActivity"> <TextView android:id="@+id/tv_word" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="24sp" android:text="@string/default_word" /> <Button android:id="@+id/btn_next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_next" /> </RelativeLayout> ``` 2. 在MainActivity.java文件中添加以下代码: ```java public class MainActivity extends AppCompatActivity { private TextView tvWord; private Button btnNext; private String[] words = {"抱头鼠窜", "胸无点墨", "如鱼得水", "头破血流", "鼠目寸光", "狗急跳墙", "亡羊补牢"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvWord = (TextView) findViewById(R.id.tv_word); btnNext = (Button) findViewById(R.id.btn_next); btnNext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int index = (int) (Math.random() * words.length); tvWord.setText(words[index]); } }); } } ``` 这个应用程序中,我们使用了一个String类型的数组来存储所有的词汇,然后通过Math.random()方法来随机获取一个词汇,并将其显示在TextView控件上。每次点击Button按钮时都会更新TextView的文本内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值