1.问题描叙
接到用户抱怨无法修改表架构:
2.查因过程
查看当前DB活动:
Select sid,serial#,osuser,program,terminal,sql_id,blocking_session,event,p1raw,p1text,p1,p2text,p2text,p2,p3text,p3,seconds_in_wait,state
from v$session where wait_class<>'Idle'
output:
当下,DB内存在很多enq:TT–content等待事件,其中红框内是smon进程,它在等待什么呢,结合ID2的定义,猜想应该是在做空间回收
ID1/ ID2的含义如下:
id1是tablespace number,ID2表明执行中的操作类型。以下是操作类型对应代码;
0- 用以避免在drop tablespace和创建rollback segment之间发生死锁
1- 用以串行化在给定表空间上创建数据文件
2- 用以避免在TSPITR tablespace point in time recovery期间发生其他类型操作
4- 用以在创建tablespace时锁住该tablespace id
8- 用以避免在ALTER TABLESPACE期间发生死锁
16- 即16进制的0×10,用以同步 分配和回收盘区,allocation and deallocation of extents.
32+ 用在增加数据文件add datafile和创建表空间时,其中ID2为 32(十进制的)+相对文件号relative file number
先看看ID1的情况:
SELECT * FROM V$TABLESPACE WHERE TS#=15;
TS# NAME INC BIG FLA ENC
---------- ------------------------------ --- --- --- ---
15 CES_DATA YES NO YES
对应的tablespace是CES_DATA,在来看CES_DATA表空间的情况
SQL> SELECT FILE_NAME,FILE_ID,TABLESPACE_NAME,BYTES/1024/1024 SIZE_IN_MB,MAXBYTES/1024/1024 MAXBYTES_IN_MB,ONLINE_STATUS FROM DBA_DATA_FILES WHERE TABLESPACE_NAME='CES_DATA';
FILE_NAME FILE_ID TABLESPACE_NAME SIZE_IN_MB MAXBYTES_IN_MB ONLINE_
---------------------------------------- ---------- ------------------------------ ---------- -------------- -------
/u2/oradata/pcicvs01/CES_DATA09.dbf 12 CES_DATA 27600 32767.9844 ONLINE
/u5/oradata/pcicvs01/CES_DATA.dbf 17 CES_DATA OFFLINE
/u4/oradata/pcicvs01/CES_DATA.dbf 18 CES_DATA 10000 10000 ONLINE
/u5/oradata/pcicvs01/CES_DATA01.dbf 22 CES_DATA 10000 10000 ONLINE
/u5/oradata/pcicvs01/CES_DATA02.dbf 24 CES_DATA 10240 10240 ONLINE
/u5/oradata/pcicvs01/CES_DATA03.dbf 25 CES_DATA 10000 0 ONLINE
/u5/oradata/pcicvs01/CES_DATA04.dbf 26 CES_DATA 10000 0 ONLINE
/u5/oradata/pcicvs01/CES_DATA05.dbf 27 CES_DATA 10240 10240 ONLINE
/u5/oradata/pcicvs01/CES_DATA06.dbf 28 CES_DATA 32765.0625 32767.9844 ONLINE
/u5/oradata/pcicvs01/CES_DATA07.dbf 29 CES_DATA 32766.0625 32767.9844 ONLINE
/u5/oradata/pcicvs01/CES_DATA08.dbf 30 CES_DATA 8672 20480 ONLINE
FILE_NAME FILE_ID TABLESPACE_NAME SIZE_IN_MB MAXBYTES_IN_MB ONLINE_
---------------------------------------- ---------- ------------------------------ ---------- -------------- -------
/u2/oradata/pcicvs01/CES_DATA10.dbf 31 CES_DATA 100 32767.9844 ONLINE
/u3/oradata/pcicvs01/CES_DATA11.dbf 32 CES_DATA 100 32767.9844 ONLINE
/u3/oradata/pcicvs01/CES_DATA12.dbf 33 CES_DATA 100 32767.9844 ONLINE
/u4/oradata/pcicvs01/CES_DATA13.dbf 34 CES_DATA 100 32767.9844 ONLINE
不幸的是看到file_id 17的文件是offline的状态,难道是offline的文件导致smon进程无法正常回收空间? (由这是一台测试DB,不清楚谁offline了这个DB,也因为没有启用archivelog,也无法将它on起来)
带着这个疑问,我们继续看看file_id 17的文件都有什么?
SQL> SELECT segment_name, segment_type, header_file, relative_fno, header_block,
bytes/POWER(1024, 2) AS "SIZE_MB"
FROM dba_segments
WHERE relative_fno=17
SEGMENT_NAME SEGMENT_TYPE HEADER_FILE RELATIVE_FNO HEADER_BLOCK SIZE_MB
--------------------------------------------------------------------------------- ------------------ ----------- ------------ ------------ ----------
17.767907 TEMPORARY 17 17 767907 .0625
17.767915 TEMPORARY 17 17 767915 .125
17.767907 TEMPORARY 17 17 767907 .0625
17.767915 TEMPORARY 17 17 767915 .125
从输出来看,这个被offline的数据文件,都是由"Header File ID.Header Block ID"格式组成的segment_name,而且segment_type是TEMPORARY,说明都是一些临时段
当听到术语 TEMPORARY 时,可能会在临时表空间中的尋找相關的segment,例如当连接表或执行不适合内存的排序操作时。
但这样的segment也可能存在于永久表空间中。 当执行以下操作之一时,就会创建这样的段。
ALTER TABLE … MOVE
CREATE TABLE … AS SELECT
CREATE INDEX …
ALTER INDEX … REBUILD
在这些操作期间,会创建一个 TEMPORARY 段。 当操作意外终止时,这些段不会被清除。
3.根因
在这里,原因就很清楚了,有人意外offline了file_id为17的数据文件,导致文件内事先存在的临时段没有被清除,当用户视图修改段结构时,等待smon进程清除临时段后释放在tablespace上的lock
看一下oracle对TT锁的描叙:
SQL> select * from v$lock_type where type='TT';
TYPE NAME ID1_TAG ID2_TAG IS_ DESCRIPTION
-------------------- ------------------------------ ------------------------------ ------------------------------ --- ------------------------------------------------------------
TT Tablespace tablespace ID operation NO Serializes DDL operations on tablespaces
4.处理过程
4.1 Mark目标segment为CORRUPT
PL/SQL 包 DBMS_SPACE_ADMIN 用于手动清理 TEMPORARY 段。 在第一步中,需要将段17.767907 标记为CORRUPT。 结合RELATIVE_FNO的值。
BEGIN
DBMS_SPACE_ADMIN.SEGMENT_CORRUPT(
tablespace_name => 'CESUSER',
header_relative_file => 17,
header_block => 767907,
corrupt_option => DBMS_SPACE_ADMIN.SEGMENT_MARK_CORRUPT
);
END;
/
4.2 Drop目标segment
将段标记为损坏后,可以将其删除。
SQL> BEGIN
DBMS_SPACE_ADMIN.SEGMENT_DROP_CORRUPT(
tablespace_name => 'CES_DATA',
header_relative_file => 17,
header_block => 767907
);
END;
/
4.3 释放占用的空间
此时该段被删除,但其占用的空间在DBA_FREE_SPACE中不可见。
SQL> SELECT SUM(bytes)/POWER(1024,3) AS "FREE_SPACE"
FROM dba_free_space
WHERE tablespace_name = 'CES_DATA';
FREE_SPACE
----------
192.136215
最后,需要重建表空间的位图。
SQL> BEGIN
DBMS_SPACE_ADMIN.TABLESPACE_REBUILD_BITMAPS(
tablespace_name => 'USERS'
);
END;
/
现在,可用空间随着删除段的大小而增加。
SQL> SELECT SUM(bytes)/POWER(1024,3) AS "FREE_SPACE"
FROM dba_free_space
WHERE tablespace_name = 'CES_DATA';
FREE_SPACE
----------
250.273469