数据字典视图是在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对对象名的解析顺序:
首先检查当前用户模式中是否存在表或视图
如果没有,检查私有同义词是否存在,有,则使用该同义词引用的对象。
如果依旧没有,检查公用同义词是否存在,有则引用该同义词的同名对象,没有则返回ORA-00942错误。