研究数据字典和基表,发现处理手工删除fs$或者file$等问题的新思路

联系:QQ(5163721)

标题:研究数据字典和基表,发现处理手工删除fs$或者file$等问题的新思路

作者:Lunar©版权所有[文章允许转载,但必须以链接方式注明源地址,否则追究法律责任.]

在测试环境玩什么东西忘记了,反正是忽然发现有个没用的表空间“UNDOTBS1”删除不掉,以前写过一篇,如何查找某个对象的定义(V$_X$_DBA)
这里重温一下数据字典和动态性能视图:
UNDOTBS1在v$tablespace中可见,但是不能drop,在dba_tablespaces中不可见,说明数据字典和动态性能视图不匹配了(手工删除了基表导致的,忘记是删除了ts$还是file$内容了):

不得不说Oracle 11.2.0.3以后的版本,对于数据库的一致性校验进行了很人性化的改动,以前这种情况是crash的,现在还open着,带病工作,O(∩_∩)O哈哈~
类似的带病工作的情况,还涉及到很多数据字典的不一致情况,比如以前的i_dependency1, i_dependency2等等。
从这个研究,也证实了如下结论:
V$TABLESPACE的信息是来源于GV$TABLESPACE,GV$TABLESPACE来源于基表 X$KCCTS
而DBA_TABLESPACES是来源于 SYS.TS$ TS 和 SYS.X$KCFISTSA。也就是说,V$TABLESPACE的信息来源于控制文件,而DBA_TABLESPACES的信息是来源于其他基表,手工删除基表信息时,其信息不和控制文件信息同步。

下面有具体看看:

[oracle@lunar ~]$ ss

SQL*Plus: Release 11.2.0.3.0 Production on Fri Nov 29 10:36:55 2013

Copyright (c) 1982, 2011, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning and Real Application Testing options

SYS@bb>select name from v$tablespace;

NAME
------------------------------------------------------------
SYSTEM
SYSAUX
UNDOTBS1
TEMP
USERS
DBTK
LUNAR
UNDOTBS2

8 rows selected.

SYS@bb>drop tablespace undotbs1;
drop tablespace undotbs1
*
ERROR at line 1:
ORA-00959: tablespace 'UNDOTBS1' does not exist


SYS@bb>
SYS@bb>select tablespace_name from dba_tablespaces;     

TABLESPACE_NAME
------------------------------------------------------------
SYSTEM
SYSAUX
TEMP
USERS
DBTK
LUNAR
UNDOTBS2

7 rows selected.

SYS@bb>       

看下创建动态性能视图的语句:

[oracle@lunar ~]$ cat /u01/app/oracle/product/11.2.0.3/dbhome_1/rdbms/admin/catalog.sql |grep -v Rem|grep fixed
@@cdfixed.sql
[oracle@lunar ~]$ 
[oracle@lunar ~]$ cat /u01/app/oracle/product/11.2.0.3/dbhome_1/rdbms/admin/cdfixed.sql |grep -v Rem|grep fixed
create or replace view v_$fixed_table as select * from v$fixed_table;   --- v_$fixed_table  实际上是 v$fixed_table 的view
create or replace public synonym v$fixed_table for v_$fixed_table;	--- v$fixed_table   是  v_$fixed_table 的同义词
grant select on v_$fixed_table to select_catalog_role;
create or replace view v_$fixed_view_definition as			--- v_$fixed_view_definition  实际上是 v$fixed_view_definitiond view
   select * from v$fixed_view_definition;
create or replace public synonym v$fixed_view_definition		--- v$fixed_view_definition 是 v_$fixed_view_definition 的同义词
   for v_$fixed_view_definition;
grant select on v_$fixed_view_definition to select_catalog_role;
create or replace view v_$indexed_fixed_column as			--- v_$indexed_fixed_column  实际上是 v$indexed_fixed_column 的view
  select * from v$indexed_fixed_column;
create or replace public synonym v$indexed_fixed_column			--- v$indexed_fixed_column   是  v_$indexed_fixed_column 的同义词
   for v_$indexed_fixed_column;
grant select on v_$indexed_fixed_column to select_catalog_role;
-- Add SQL Performance Analyzer (SPA) fixed views
remark Create synonyms for the global fixed views			-- global fixed view实际上是从Oracle 8引入的,因为这个版本,Oracle对OPS进行了增强,																																		--- 添加GV$视图就是为了方便全局管理,V$跟GV$的区别就在这里“where inst_id = USERENV('Instance')”
--- 也就是V$是本实例的视图,而GV$是全局视图																																						
create or replace view gv_$fixed_table as select * from gv$fixed_table;	 --- gv_$fixed_table  实际上是 gv$fixed_table 的view
create or replace public synonym gv$fixed_table for gv_$fixed_table;	--- gv$fixed_table   是  gv_$fixed_table 的同义词
grant select on gv_$fixed_table to select_catalog_role;		
create or replace view gv_$fixed_view_definition as			--- gv_$fixed_view_definition  实际上是 gv$fixed_view_definition 的view
   select * from gv$fixed_view_definition;
create or replace public synonym gv$fixed_view_definition											
   for gv_$fixed_view_definition;
grant select on gv_$fixed_view_definition to select_catalog_role;
create or replace view gv_$indexed_fixed_column as			--- gv_$indexed_fixed_column  实际上是 gv$indexed_fixed_column 的view
  select * from gv$indexed_fixed_column;
create or replace public synonym gv$indexed_fixed_column											
   for gv_$indexed_fixed_column;
grant select on gv_$indexed_fixed_column to select_catalog_role;
[oracle@lunar ~]$ 

通过上面建库脚本也可以清晰的看到,得到授权的普通用户仍然只能访问V$开头的视图,而不能直接访问V_$开头的视图,因为实际上V$视图是V_$视图的公有同义词(PUBLIC SYNONYM)要想访问V_$必须带上SYS.V_$,例如

set heading off echo off long 100000 pages 10000
select * from v$fixed_view_definition where view_name='V$TABLESPACE';

SYS@bb>select * from v$fixed_view_definition where view_name='V$TABLESPACE';

V$TABLESPACE
select  TS# , NAME, INCLUDED_IN_DATABASE_BACKUP, BIGFILE, FLASHBACK_ON, ENCRYPT_IN_BACKUP from GV$TABLESPACE where inst_id = USERENV('Instance')


SYS@bb>select * from v$fixed_view_definition where view_name='GV$TABLESPACE';

GV$TABLESPACE
select inst_id,tstsn,tsnam,       decode(bitand(tsflg, 1+2), 1, 'NO', 2,'NO','YES'),  decode(bitand(tsflg, 4), 4,'YES','NO'),  decode(bitand(tsflg,
8), 8,'NO','YES'),  decode(bitand(tsflg, 16+32), 16, 'ON', 32, 'OFF', to_char(null)) from x$kccts where tstsn != -1


SYS@bb>

而查看普通的DBA_ ALL_ USER_ 等视图,可以查看数据字典 dba_views(这个视图从8i开始引入的)
例如:

set heading off echo off long 1000000000 pages 10000
select text from dba_views where view_name ='DBA_TABLESPACES';

SYS@bb>select text from dba_views where view_name ='DBA_TABLESPACES';

select ts.name, ts.blocksize, ts.blocksize * ts.dflinit,
          decode(bitand(ts.flags, 3), 1, to_number(NULL),
                 ts.blocksize * ts.dflincr),
          ts.dflminext,
          decode(ts.contents$, 1, to_number(NULL), ts.dflmaxext),
          decode(bitand(ts.flags, 4096), 4096, ts.affstrength, NULL),
          decode(bitand(ts.flags, 3), 1, to_number(NULL), ts.dflextpct),
          ts.blocksize * ts.dflminlen,
          decode(ts.online$, 1, 'ONLINE', 2, 'OFFLINE',
                 4, 'READ ONLY', 'UNDEFINED'),
          decode(ts.contents$, 0, (decode(bitand(ts.flags, 16), 16, 'UNDO',
                 'PERMANENT')), 1, 'TEMPORARY'),
          decode(bitand(ts.dflogging, 1), 0, 'NOLOGGING', 1, 'LOGGING'),
          decode(bitand(ts.dflogging, 2), 0, 'NO', 2, 'YES'),
          decode(ts.bitmapped, 0, 'DICTIONARY', 'LOCAL'),
          decode(bitand(ts.flags, 3), 0, 'USER', 1, 'SYSTEM', 2, 'UNIFORM',
                 'UNDEFINED'),
          decode(ts.plugged, 0, 'NO', 'YES'),
          decode(bitand(ts.flags,32), 32,'AUTO', 'MANUAL'),
          decode(bitand(ts.flags,64), 64,'ENABLED', 'DISABLED'),
          decode(bitand(ts.flags,16), 16, (decode(bitand(ts.flags, 512), 512,
                 'GUARANTEE', 'NOGUARANTEE')), 'NOT APPLY'),
          decode(bitand(ts.flags,256), 256, 'YES', 'NO'),
          decode(tsattr.storattr, 1, 'STORAGE', 'HOST'),
          decode(bitand(ts.flags,16384), 16384, 'YES', 'NO'),
          decode(bitand(ts.flags,64), 0, null,
            (case when bitand(ts.flags,  65536) = 65536
                    then 'OLTP'
                  when bitand(ts.flags, (131072+262144)) = 131072
                    then 'QUERY LOW'
                  when bitand(ts.flags, (131072+262144)) = 262144
                    then 'QUERY HIGH'
                  when bitand(ts.flags, (131072+262144)) = (131072+262144)
                    then 'ARCHIVE LOW'
                  when bitand(ts.flags, 524288) = 524288
                    then 'ARCHIVE HIGH'
                  else 'BASIC' end))
from sys.ts$ ts, sys.x$kcfistsa tsattr
where ts.online$ != 3
and bitand(flags,2048) != 2048
and ts.ts# = tsattr.tsid


SYS@bb>

X$ 是 Oracle 数据库 的核心部分,这些表用于跟踪内部数据库信息,维护数据库的正常运行。 X$ 表是加密的(除了MOS和直接看源代码以外,我不知道还有什么方法可以查看X$视图)
Oracle 通过 X$和一些基表(TS$, OBJ$, SEG$等)建立起其他大量视图,提供用户查询和管理数据库。
在9i以前
另外,还可以通过X$KQFTA来查看X$表的相关信息:

X$KQFTA
   [K]ernel [Q]uery [F]ixed Tables/views Management
    [TA]bles

 Column          Type               Description
 --------        ----               --------
 ADDR            RAW(4)             address of this row/entry in the array or SGA
 INDX            NUMBER             index number of this row in the fixed table array
 INST_ID         NUMBER       8.x   oracle instance number
 KQFTAOBJ        NUMBER             object ID number - hardcoded in kernel
 KQFTAVER        NUMBER             version number
 KQFTANAM        VARCHAR2(30)       table name

 KQFTATYP        NUMBER             type of table
     KQFTVTTB  1      declared using KQFTABL
     KQFTVTTP  2      declared using KQFTABP
     KQFTVTVI  3      declared using KQFVIEW
     KQFTVTCB  4      declared using KQFTABC
     KQFTVTIC  5      declared using KQFTABIC
     KQFTVTTS  6      declared using KQFTABS

 KQFTAFLG        NUMBER             flag
     KQFTVFONE  1      the INDX column of the table is one based 

 KQFTARSZ        NUMBER             array element size
 KQFTACOC        NUMBER             column count
 
SYS@bb>select  KQFTAOBJ, KQFTANAM, KQFTATYP from X$KQFTA where KQFTANAM='X$KCFISTSA';

  KQFTAOBJ KQFTANAM                                                       KQFTATYP
---------- ------------------------------------------------------------ ----------
4294952982 X$KCFISTSA                                                            5   

SYS@bb>

类似,就是11.2中新引入的X$表:
[oracle@lunar bin]$ strings oracle|grep KCFISTSA
X$KCFISTSA
[oracle@lunar bin]$

在10g和10g以前是没有的:

[oracle@lunar ~]$ . ora102.env 
[oracle@lunar ~]$ cd $ORACLE_HOME
[oracle@lunar db_1]$ cd bin
[oracle@lunar bin]$ strings oracle|grep KCFISTSA
[oracle@lunar bin]$ 

实际上,在10g以前的数据库中,
set heading off echo off long 1000000000 pages 10000
select text from dba_views where view_name =’X$KCFISTSA’;

基表数据字典是根据sql.bsq创建的:

[oracle@lunar ~]$ cat /u01/app/oracle/product/11.2.0.3/dbhome_1/rdbms/admin/sql.bsq |grep -v rem|grep -v Rem
dcore.bsq
dsqlddl.bsq
dmanage.bsq
dplsql.bsq
dtxnspc.bsq
dfmap.bsq
denv.bsq
drac.bsq
dsec.bsq
doptim.bsq
dobj.bsq
djava.bsq
dpart.bsq
drep.bsq
daw.bsq
dsummgt.bsq
dtools.bsq
dexttab.bsq
ddm.bsq
dlmnr.bsq
ddst.bsq
[oracle@lunar ~]$ 

回到我们的正题,通过上面查询可以看到,V$TABLESPACE的信息是来源于GV$TABLESPACE,GV$TABLESPACE来源于基表 X$KCCTS
而DBA_TABLESPACES是来源于 SYS.TS$ TS 和 SYS.X$KCFISTSA。也就是说,V$TABLESPACE的信息来源于控制文件,而DBA_TABLESPACES的信息是来源于其他基表,手工删除基表信息时,其信息不和控制文件信息同步,X$KCCTS定义如下

[K]ernel [C]ache [C]ontrolfile management [T]able[S]pace record

 Column          Type               Description
 --------        ----               -----------
 ADDR            RAW(4)             address of this row/entry in the SGA
 INDX            NUMBER             index number of this row in the fixed table array
 INST_ID         NUMBER             oracle instance number
 TSRNO           NUMBER             rec#
 TSTSN           NUMBER             TableSpace Number (same as ts# in data dict.)    =================关联TS$.TS#
 TSNAM           VARCHAR2(30)       tablespace NAMe																	 =================表空间名称
 TSNRB           NUMBER        8.0  Number of Rollback Segments in the tablespace

 TSFLG           NUMBER        8.1  (rollback segments) Flags defining tablespace
     KCCTSFTM  0x0001      Tablespace is temporary - Has only tempfiles

 TSDFP           NUMBER             tablespace's 1st DataFile Pointer (DataFile rec#)
 TSPSS           VARCHAR2(16)       ts Point-in-time recovery mode Start Scn
 TSPST           VARCHAR2(20)       ts Point-in-time recov mode Start Timestamp
 TSPCS           VARCHAR2(16)       last ts Point-in-time recovery Completion Scn
 TSPCT           VARCHAR2(20)       last ts Point-in-time recov Completion Timestp

Bug 13832069 : QUERY USING DBA_TABLESPACES (X$KCFISTSA) CAN LEAK CURSORS AND GIVE WRONG RESULTS

而X$KCFISTSA是定义在kcfis2.h中的,其结构定义如下:

SYS@bb>desc sys.X$KCFISTSA
 Name                                                                               Null?    Type
 ---------------------------------------------------------------------------------- -------- -------------------------------------------------------
 ADDR                                                                                        RAW(8)
 INDX                                                                                        NUMBER
 INST_ID                                                                                     NUMBER
 TSID                                                                                        NUMBER
 STORATTR                                                                                    NUMBER

SYS@bb>

ADDR RAW
		Address of buffer used to store row.
INDX NUMBER
		Index number (used to uniquely differentiate rows).
INST_ID NUMBER
		Instance number.
TSID NUMBER
		Based on struct element tsid_kcfistsa.
		tsid_kcfistsa was found in file kcfis2.h, line 377 and is described as :
Tablespace ID
STORATTR NUMBER
		Based on struct element storattr_kcfistsa.
		storattr_kcfistsa was found in file kcfis2.h, line 378 and is described as :
		Tablespace storage attributes

具体请参考大师的说明:
http://www.juliandyke.com/Internals/FixedTables/X_KCFISTSA.html

再来看看ts$的定义:

SYS@bb>desc sys.TS$;
 Name                                                                               Null?    Type
 ---------------------------------------------------------------------------------- -------- -------------------------------------------------------
 TS#                                                                                NOT NULL NUMBER
 NAME                                                                               NOT NULL VARCHAR2(30)
 OWNER#                                                                             NOT NULL NUMBER
 ONLINE$                                                                            NOT NULL NUMBER
 CONTENTS$                                                                          NOT NULL NUMBER
 UNDOFILE#                                                                                   NUMBER
 UNDOBLOCK#                                                                                  NUMBER
 BLOCKSIZE                                                                          NOT NULL NUMBER
 INC#                                                                               NOT NULL NUMBER
 SCNWRP                                                                                      NUMBER
 SCNBAS                                                                                      NUMBER
 DFLMINEXT                                                                          NOT NULL NUMBER
 DFLMAXEXT                                                                          NOT NULL NUMBER
 DFLINIT                                                                            NOT NULL NUMBER
 DFLINCR                                                                            NOT NULL NUMBER
 DFLMINLEN                                                                          NOT NULL NUMBER
 DFLEXTPCT                                                                          NOT NULL NUMBER
 DFLOGGING                                                                          NOT NULL NUMBER
 AFFSTRENGTH                                                                        NOT NULL NUMBER
 BITMAPPED                                                                          NOT NULL NUMBER
 PLUGGED                                                                            NOT NULL NUMBER
 DIRECTALLOWED                                                                      NOT NULL NUMBER
 FLAGS                                                                              NOT NULL NUMBER
 PITRSCNWRP                                                                                  NUMBER
 PITRSCNBAS                                                                                  NUMBER
 OWNERINSTANCE                                                                               VARCHAR2(30)
 BACKUPOWNER                                                                                 VARCHAR2(30)
 GROUPNAME                                                                                   VARCHAR2(30)
 SPARE1                                                                                      NUMBER
 SPARE2                                                                                      NUMBER
 SPARE3                                                                                      VARCHAR2(1000)
 SPARE4                                                                                      DATE

SYS@bb>

在TS$中,我昨天手工清理了一条NAME=UNDOTBS1的记录,这就是V$TABLESPACE和DBA_TABLESPACES中表空间名称不一致的原因

SYS@bb>select ts#, name, online$ from ts$;

       TS# NAME                                                            ONLINE$
---------- ------------------------------------------------------------ ----------
         0 SYSTEM                                                                1
         1 SYSAUX                                                                1
         3 TEMP                                                                  1
         4 USERS                                                                 1
         5 LMTBSB                                                                3
         6 DBTK                                                                  1
         7 YKDBAWRTS1                                                            3
         8 LUNAR                                                                 1
         9 UNDOTBS                                                               3
        10 UNDOTBS2                                                              1

10 rows selected.

SYS@bb>

可以看到,除了我手工删除的一条记录(UNDOTBS1)以外,所有数据库创建以来的表空间名称等信息都保留在TS$中,这样的设计,我猜是为了能够重用表空间名称,减少基表更新等操作(性能考虑吧? 我也不知道,O(∩_∩)O哈哈~)
比如,这里的UNDOTBS和YKDBAWRTS1等都已经是被删除的表空间。

再看看还有那些依赖于X$KCFISTSA的数据字典:
通过查询dependency$,我们可以发现有3个对象依赖于 X$KCFISTSA基表:

SYS@bb>select * from dependency$ where P_OBJ#=4294952982;

    D_OBJ# D_TIMESTAMP             ORDER#     P_OBJ# P_TIMESTAMP           D_OWNER#   PROPERTY D_ATTRS         D_REASON
---------- ------------------- ---------- ---------- ------------------- ---------- ---------- --------------- ---------------
      4943 2013-06-23 09:37:34          0 4294952982 1991-01-02 00:00:00                     5 0003000030
      4945 2013-06-23 09:37:34          0 4294952982 1991-01-02 00:00:00                     5 0003000030
     12409 2013-06-23 09:45:16         30 4294952982 1991-01-02 00:00:00                     5 0003000030

SYS@bb>
SYS@bb>desc dependency$
 Name                                                                               Null?    Type
 ---------------------------------------------------------------------------------- -------- -------------------------------------------------------
 D_OBJ#                                                                              NOT NULL NUMBER
 D_TIMESTAMP                                                                        NOT NULL DATE
 ORDER#                                                                             NOT NULL NUMBER
 P_OBJ#                                                                             NOT NULL NUMBER
 P_TIMESTAMP                                                                        NOT NULL DATE
 D_OWNER#                                                                                    NUMBER
 PROPERTY                                                                           NOT NULL NUMBER
 D_ATTRS                                                                                     RAW(2000)
 D_REASON                                                                                    RAW(2000)

SYS@bb>
1

知道了这个就很清晰了,处理思路:
1,针对file$的不一致信息,需要手工清除:

SYS@bb>select file#,status$,ts# from file$ where ts#=2;

     FILE#    STATUS$        TS#
---------- ---------- ----------
         3          2          2

SYS@bb>

2,可以根据11g的新特性Health Manager的检查结果来判断,还有哪些相关对象不一致的,是否需要手工清理:

SYS@bb>select obj#,ts#,file# from tab$ where ts#=2;

no rows selected

SYS@bb>select obj#,ts#,file# from ind$ where ts#=2;

no rows selected

SYS@bb>

3,当其他信息都一致后,针对X$KCCTS的不一致信息,由于其来源于控制文件,那么重建控制文件解决

			SYS@bb>select TSTSN,TSNAM from X$KCCTS where TSNAM='UNDOTBS1';
			
			     TSTSN TSNAM
			---------- ------------------------------------------------------------
			         2 UNDOTBS1
			
			SYS@bb>

之前就是这个思路错误了,导致了一堆的其他问题,当然,也知道和跟多其他好玩东西,比如用gdb跳过数据库启动时的数据字典检查项,知道了重建控制文件的风险其实很大(在不了解现场情况和重建控制文件的细节时)……

此条目发表在 FAQ, Internal 分类目录,贴了 , , , , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注