数据字典视图是在X$表和数据字典表之上创建的视图,在创建数据库时由$ORACLE_HOME/rdbms/admin/catalog.sql中列出的*.sql脚本创建,按照前缀的不同可以分为3类:

USER_: 用户所拥有的相关对象信息。

ALL_:用于有权限访问的所有对象信息。

DBA_:数据库所有相关对象信息。

通常USER_视图不包含owner字段,查询返回的是当前用户的对象信息。举个例子:

create or replace view USER_TABLES
    (TABLE_NAME, TABLESPACE_NAME, CLUSTER_NAME, IOT_NAME, STATUS,
     PCT_FREE, PCT_USED,
     INI_TRANS, MAX_TRANS,
     INITIAL_EXTENT, NEXT_EXTENT,
     MIN_EXTENTS, MAX_EXTENTS, PCT_INCREASE,
     FREELISTS, FREELIST_GROUPS, LOGGING,
     BACKED_UP, NUM_ROWS, BLOCKS, EMPTY_BLOCKS,
     AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN,
     AVG_SPACE_FREELIST_BLOCKS, NUM_FREELIST_BLOCKS,
     DEGREE, INSTANCES, CACHE, TABLE_LOCK,
     SAMPLE_SIZE, LAST_ANALYZED, PARTITIONED,
     IOT_TYPE, TEMPORARY, SECONDARY, NESTED,
     BUFFER_POOL,  FLASH_CACHE,
     CELL_FLASH_CACHE, ROW_MOVEMENT,
     GLOBAL_STATS, USER_STATS, DURATION, SKIP_CORRUPT, MONITORING,
     CLUSTER_OWNER, DEPENDENCIES, COMPRESSION, COMPRESS_FOR,DROPPED, READ_ONLY,
     SEGMENT_CREATED,RESULT_CACHE)
select o.name,
       decode(bitand(t.property,2151678048), 0, ts.name,
              decode(t.ts#, 0, null, ts.name)),
       decode(bitand(t.property, 1024), 0, null, co.name),
       decode((bitand(t.property, 512)+bitand(t.flags, 536870912)),
              0, null, co.name),
       ......
from sys.ts$ ts, sys.seg$ s, sys.obj$ co, sys.tab$ t, sys.obj$ o,
     sys.deferred_stg$ ds, sys.obj$ cx, sys.user$ cu, x$ksppcv ksppcv,
     x$ksppi ksppi
where o.owner# = userenv('SCHEMAID')

从DDL语句中看到where o.owner# = userenv('SCHEMAID')这个条件,就是限制返回当前schema对象的信息。在ALL_TABLES表中的where中增加了以下的条件:

 (o.owner# = userenv('SCHEMAID')
       or o.obj# in
            (select oa.obj#
             from sys.objauth$ oa
             where grantee# in ( select kzsrorol
                                 from x$kzsro
                               )
            )
       or /* user has system privileges */
         exists (select null from v$enabledprivs
                 where priv_number in (-45 /* LOCK ANY TABLE */,
                                       -47 /* SELECT ANY TABLE */,
                                       -48 /* INSERT ANY TABLE */,
                                       -49 /* UPDATE ANY TABLE */,
                                       -50 /* DELETE ANY TABLE */)
                 )
      )

这里面定义了权限/* user has system privileges */ 用户拥有访问权限的对象

而DBA_TABLES视图中WHERE条件中没有这方面的限制,这里就不在列举了。

前面几篇转帖分别对Oracle的X$表、全局视图、动态性能视图、数据字典都做了解释。我们进一步研究:

SQL> select count(*) from v$fixed_table where name like 'X$%';
  COUNT(*)
----------
       945

可以看到Oracle 11g下有945个X$表

SQL> select count(*) from v$fixed_table where name like 'GV$%';
  COUNT(*)
----------
       496

Oracle 11g下有496个GV$表

SQL> select count(*) from v$fixed_table where name like 'V$%';
  COUNT(*)
----------
       525

Oracle 11g下有525个V$表,三个对象总数为945+496+525=1966,而实际v$fixed_table有1968个对象,通过以下语句可以获取剩余的对象:

SQL> select name from (select name from (select name from v$fixed_table where name not like 'X$%') where name not like 'V$%') where name not like 'GV$%';
NAME
--------------------------------------------------------------------------------
GO$SQL_BIND_CAPTURE
O$SQL_BIND_CAPTURE

我们在来回看以下V$_和GV$_视图的创建语句,就能明白数据库构建过程

SQL> select view_definition from v$fixed_view_definition where view_name='V$PARAMETER';
VIEW_DEFINITION
--------------------------------------------------------------------------------
select  NUM , NAME , TYPE , VALUE , DISPLAY_VALUE, ISDEFAULT , ISSES_MODIFIABLE
, ISSYS_MODIFIABLE , ISINSTANCE_MODIFIABLE, ISMODIFIED , ISADJUSTED , ISDEPRECAT
ED, ISBASIC, DESCRIPTION, UPDATE_COMMENT, HASH  from GV$PARAMETER where inst_id
= USERENV('Instance')
VIEW_DEFINITION
--------------------------------------------------------------------------------
select x.inst_id,x.indx+1,ksppinm,ksppity,ksppstvl, ksppstdvl, ksppstdf,  decode
(bitand(ksppiflg/256,1),1,'TRUE','FALSE'),  decode(bitand(ksppiflg/65536,3),1,'I
MMEDIATE',2,'DEFERRED',                                  3,'IMMEDIATE','FALSE'),
  decode(bitand(ksppiflg,4),4,'FALSE',                                     decod
e(bitand(ksppiflg/65536,3), 0, 'FALSE', 'TRUE')),     decode(bitand(ksppstvf,7),
1,'MODIFIED',4,'SYSTEM_MOD','FALSE'),  decode(bitand(ksppstvf,2),2,'TRUE','FALSE
'),  decode(bitand(ksppilrmflg/64, 1), 1, 'TRUE', 'FALSE'),  decode(bitand(ksppi
lrmflg/268435456, 1), 1, 'TRUE', 'FALSE'),  ksppdesc, ksppstcmnt, ksppihash  fro
m x$ksppi x, x$ksppcv y where (x.indx = y.indx) and  bitand(ksppiflg,268435456)
= 0 and  ((translate(ksppinm,'_','#') not like '##%') and    ((translate(ksppinm
,'_','#') not like '#%')      or (ksppstdf = 'FALSE') or      (bitand(ksppstvf,5
) > 0)))

看到V$PARAMETER通过GV$PARAMETER创建出来的。GV$则是通过X$KSPPI,X$KSPPCV表创建的。因此X$KSPPI,X$KSPPCV包含所有参数。

 

Oracle如何通过同义词定位对象,我在做这个实验时发现使用scott用户无法访问同义词,授予select any dictionary权限

SQL> grant select any dictionary to scott
SQL> select * from session_privs;
PRIVILEGE
--------------------------------------------------------------------------------
CREATE TRIGGER
CREATE TYPE
CREATE OPERATOR
CREATE INDEXTYPE
SELECT ANY DICTIONARY

在scott用户下,我们实际查看的是同义词:

SQL> desc sys.v$parameter
ERROR:
ORA-04043: object sys.v$parameter does not exist
SQL> desc v$parameter
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NUM                                                NUMBER
 NAME                                               VARCHAR2(80)
 TYPE                                               NUMBER
 VALUE                                              VARCHAR2(4000)
 DISPLAY_VALUE                                      VARCHAR2(4000)
 ISDEFAULT                                          VARCHAR2(9)
 ISSES_MODIFIABLE                                   VARCHAR2(5)
 ISSYS_MODIFIABLE                                   VARCHAR2(9)
 ISINSTANCE_MODIFIABLE                              VARCHAR2(5)
 ISMODIFIED                                         VARCHAR2(10)
 ISADJUSTED                                         VARCHAR2(5)
 ISDEPRECATED                                       VARCHAR2(5)
 ISBASIC                                            VARCHAR2(5)
 DESCRIPTION                                        VARCHAR2(255)
 UPDATE_COMMENT                                     VARCHAR2(255)
 HASH                                               NUMBER

通过10046事件进行跟踪

SQL> alter session set events'10046 trace name context forever,level 12'

查看跟踪信息,发现这样访问的对象直接是SYS下的视图。

*** 2015-02-07 14:27:49.123
WAIT #2: nam='SQL*Net message from client' ela= 39601170 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1423290469123022
CLOSE #2:c=0,e=26,dep=0,type=1,tim=1423290469123229
=====================
PARSING IN CURSOR #3 len=32 dep=0 uid=84 oct=3 lid=84 tim=1423290469123441 hv=2099733871 ad='1e96fe7c0' sqlid='5quus75ykftbg'
select count(*) from v$parameter
END OF STMT
PARSE #3:c=0,e=136,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=322934900,tim=1423290469123439
EXEC #3:c=0,e=66,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=322934900,tim=1423290469123604
WAIT #3: nam='SQL*Net message to client' ela= 8 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1423290469123710
WAIT #3: nam='asynch descriptor resize' ela= 6 outstanding #aio=0 current aio limit=128 new aio limit=130 obj#=-1 tim=1423290469124037
FETCH #3:c=10999,e=10824,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=322934900,tim=1423290469134582
WAIT #3: nam='SQL*Net message from client' ela= 273 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1423290469135100
FETCH #3:c=0,e=2,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=322934900,tim=1423290469135159
WAIT #3: nam='SQL*Net message to client' ela= 4 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1423290469135196
*** 2015-02-07 14:28:56.289
WAIT #3: nam='SQL*Net message from client' ela= 67154000 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1423290536289219
CLOSE #3:c=0,e=13,dep=0,type=3,tim=1423290536289399
=====================
PARSING IN CURSOR #2 len=202 dep=1 uid=0 oct=3 lid=0 tim=1423290536290959 hv=3819099649 ad='1eba6b8e0' sqlid='3nkd3g3ju5ph1'
select obj#,type#,ctime,mtime,stime, status, dataobj#, flags, oid$, spare1, spare2 from obj$ where owner#=:1 and name=:2 and namespace=:3 and remoteowner is null and linkname is null and subname is null
END OF STMT
PARSE #2:c=1000,e=201,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=2853959010,tim=1423290536290957
BINDS #2:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7fa66c164fb0  bln=22  avl=02  flg=05
  value=84
 Bind#1
  oacdty=01 mxl=32(12) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=01 csi=178 siz=32 off=0
  kxsbbbfp=7fa66c164f78  bln=32  avl=12  flg=05
  value="V$PARARMETER"
 Bind#2
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7fa66c164f48  bln=24  avl=02  flg=05
  value=1
EXEC #2:c=0,e=283,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=2853959010,tim=1423290536291448
FETCH #2:c=0,e=99,p=0,cr=3,cu=0,mis=0,r=0,dep=1,og=4,plh=2853959010,tim=1423290536291587
STAT #2 id=1 cnt=0 pid=0 pos=1 obj=18 op='TABLE ACCESS BY INDEX ROWID OBJ$ (cr=3 pr=0 pw=0 time=0 us cost=4 size=83 card=1)'
STAT #2 id=2 cnt=0 pid=1 pos=1 obj=37 op='INDEX RANGE SCAN I_OBJ2 (cr=3 pr=0 pw=0 time=0 us cost=3 size=0 card=1)'

上面需要关注的几个重要内容:

owner#=:1 这里绑定变量使用的是Bind#0(value=84)

SQL> select userenv('SCHEMAID') user_id from dual;
   USER_ID
----------
        84

name=:2 Bind#1(value="V$PARARMETER")

namespace=:3 Bind#2(value=1)

SQL> select namespace from dba_objects where object_name='V$PARAMETER';
 NAMESPACE
----------
         1

接下来再看看后续跟踪信息:

PARSING IN CURSOR #2 len=46 dep=1 uid=0 oct=3 lid=0 tim=1423294096027970 hv=1343089354 ad='1e7cb7ba8' sqlid='1mjd9xp80vuqa'
select node,owner,name from syn$ where obj#=:1
END OF STMT
PARSE #2:c=1000,e=656,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=1423294096027969
BINDS #2:
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=7f41a53b2ed8  bln=22  avl=03  flg=05
  value=1456
EXEC #2:c=2000,e=1408,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=3023518864,tim=1423294096029586
FETCH #2:c=0,e=64,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,plh=3023518864,tim=1423294096029722
STAT #2 id=1 cnt=1 pid=0 pos=1 obj=68 op='TABLE ACCESS BY INDEX ROWID SYN$ (cr=3 pr=0 pw=0 time=0 us cost=2 size=27 card=1)'
STAT #2 id=2 cnt=1 pid=1 pos=1 obj=77 op='INDEX UNIQUE SCAN I_SYN1 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)'
CLOSE #2:c=0,e=2,dep=1,type=3,tim=1423294096029924

obj#=:1 Bind#0(value=1456)

SQL> select object_name,object_type from dba_objects where object_id=1456;
OBJECT_NAME                              OBJECT_TYPE
---------------------------------------- ---------------------------------------------------------
V$PARAMETER                              SYNONYM

SQL> col node for a15
SQL> col owner for a15
SQL> col name for a15
SQL> select node,owner,name from syn$ where obj#=1456;
NODE            OWNER           NAME
--------------- --------------- ---------------
                SYS             V_$PARAMETER

通过上述可以看到在SCOTT用户下访问V$PARAMETER实际是同义词

当我执行以下语句后,继续观察跟踪日志:

SQL> select count(*) from v$parameter;
跟踪日志记录额该语句访问的对象
*** 2015-02-07 16:47:38.927
WAIT #0: nam='SQL*Net message from client' ela= 4762851266 driver id=1650815232 #bytes=1 p3=0 obj#=13482 tim=1423298858927796
=====================
PARSING IN CURSOR #5 len=37 dep=1 uid=0 oct=3 lid=0 tim=1423298858930897 hv=1398610540 ad='1e7e58310' sqlid='grwydz59pu6mc'
select text from view$ where rowid=:1
END OF STMT
PARSE #5:c=1000,e=847,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=0,tim=1423298858930895
BINDS #5:
 Bind#0
  oacdty=11 mxl=16(16) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=00 csi=00 siz=16 off=0
  kxsbbbfp=7f41a546c190  bln=16  avl=16  flg=05
  value=00000275.0004.0001
EXEC #5:c=2000,e=1439,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=4,plh=3684871272,tim=1423298858932587
FETCH #5:c=0,e=41,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,plh=3684871272,tim=1423298858932679
STAT #5 id=1 cnt=1 pid=0 pos=1 obj=69 op='TABLE ACCESS BY USER ROWID VIEW$ (cr=1 pr=0 pw=0 time=0 us cost=1 size=15 card=1)'
CLOSE #5:c=0,e=63,dep=1,type=0,tim=1423298858932782
=====================
PARSING IN CURSOR #2 len=32 dep=0 uid=84 oct=3 lid=84 tim=1423298858935834 hv=2099733871 ad='1eb550b50' sqlid='5quus75ykftbg'
select count(*) from v$parameter
END OF STMT
PARSE #2:c=7999,e=7714,p=0,cr=2,cu=0,mis=1,r=0,dep=0,og=1,plh=322934900,tim=1423298858935832
EXEC #2:c=0,e=76,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=322934900,tim=1423298858936010
WAIT #2: nam='SQL*Net message to client' ela= 8 driver id=1650815232 #bytes=1 p3=0 obj#=13482 tim=1423298858936125
FETCH #2:c=11998,e=12180,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,plh=322934900,tim=1423298858948389
STAT #2 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=0 pr=0 pw=0 time=0 us)'
STAT #2 id=2 cnt=342 pid=1 pos=1 obj=0 op='HASH JOIN  (cr=0 pr=0 pw=0 time=568 us cost=1 size=113 card=1)'
STAT #2 id=3 cnt=2389 pid=2 pos=1 obj=0 op='FIXED TABLE FULL X$KSPPI (cr=0 pr=0 pw=0 time=9426 us cost=0 size=81 card=1)'
STAT #2 id=4 cnt=2399 pid=2 pos=2 obj=0 op='FIXED TABLE FULL X$KSPPCV (cr=0 pr=0 pw=0 time=2524 us cost=0 size=3200 card=100)'
WAIT #2: nam='SQL*Net message from client' ela= 540 driver id=1650815232 #bytes=1 p3=0 obj#=13482 tim=1423298858949362
FETCH #2:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=322934900,tim=1423298858949503
WAIT #2: nam='SQL*Net message to client' ela= 5 driver id=1650815232 #bytes=1 p3=0 obj#=13482 tim=1423298858949555

rowid=:1 (Bind#0 value=00000275.0004.0001) 查询时传入的变量时rowid值,这个需要进行转换

SQL> select obj# from view$ where dbms_rowid.rowid_to_restricted(rowid,0)='00000275.0004.0001';
      OBJ#
----------
      1455
SQL> select object_name,object_type from dba_objects where object_id=1455;
OBJECT_NAME     OBJECT_TYPE
--------------- ------------------------------
V_$PARAMETER    VIEW

SQL> select text from view$ where obj#=1455;
TEXT
------------------------------------------------------------
select "NUM","NAME","TYPE","VALUE","DISPLAY_VALUE","ISDEFAULT","ISSES_MODIFIABLE","ISSYS_MODIFIABLE","ISINSTANCE_MODIFIABLE","ISMODIFIED","ISADJUSTED","ISDEPRECATED","ISBASIC","DESCRIPTION","UPDATE_COMMENT","HASH" from v$parameter

 最后总结一下SQL语句中的Oracle对对象名的解析顺序:

  1. 首先检查当前用户模式中是否存在表或视图

  2. 如果没有,检查私有同义词是否存在,有,则使用该同义词引用的对象。

  3. 如果依旧没有,检查公用同义词是否存在,有则引用该同义词的同名对象,没有则返回ORA-00942错误。