Oracle的普通用户执行dbms_xplan包查看执行计划,有时会提示错误,
SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
User has no SELECT privilege on V$SESSION
原因是该用户缺少一些动态性能视图的访问权限,但是当我们尝试将提示的v$session授予用户(例如hr)时,提示了这个错,
SQL> grant select on v$session to hr;
grant select on v$session to hr
*
ERROR at line 1:
ORA-02030: can only select from fixed tables/views
这就有些玄机了,我是最早从eygle的书中看到的这个问题,一个普通用户,在未授权vsession访问权限的前提下,执行desc vsession,他提示的是v_session,不是vsession,v_session和vsession,有什么区别?结合上面的grant错误,应该如何授权?
SQL> desc v$session;
ERROR:
ORA-04043: object "SYS"."V_$SESSION" does not exist
首先,我们常用的v$session其实是个同义词,
SQL> select object_name, object_type, owner from dba_objects where object_name='V$SESSION';
OBJECT_NAME OBJECT_TYPE OWNER
------------------------- ----------------------- ---------------
V$SESSION SYNONYM PUBLIC
看下他的定义,他是v_$session的同义词,
SQL> select dbms_metadata.get_ddl('SYNONYM','V$SESSION','PUBLIC') from dual;
DBMS_METADATA.GET_DDL('SYNONYM','V$SESSION','PUBLIC')
--------------------------------------------------------------------------------
CREATE OR REPLACE NONEDITIONABLE PUBLIC SYNONYM "V$SESSION" FOR "SYS"."V_$SESSION"
而v_$session是个视图,
SQL> select object_name, object_type, owner from dba_objects where object_name='V_$SESSION';
OBJECT_NAME OBJECT_TYPE OWNER
------------------------- ----------------------- ---------------
V_$SESSION VIEW SYS
这是他的定义,我们看到结尾,v_session是从vsession视图得到的,
SQL> select dbms_metadata.get_ddl('VIEW','V_$SESSION','SYS') from dual;
DBMS_METADATA.GET_DDL('VIEW','V_$SESSION','SYS')
--------------------------------------------------------------------------------
CREATE OR REPLACE FORCE NONEDITIONABLE VIEW "SYS"."V_$SES
SION" CONTAINER_DATA
("SADDR", "SID", "SERIAL#", "AUDSID", "PADDR", "USER#",
"USERNAME", "COMMAND", "OWNERID", "TADDR
", "LOCKWAIT", "STATUS", "SERVER", "SCHE
MA#", "SCHEMANAME", "OSUSER", "PROCESS",
"MACHINE", "PORT", "TERMINAL", "PROGRAM
", "TYPE", "SQL_ADDRESS", "SQL_HASH_VALU
E", "SQL_ID", "SQL_CHILD_NUMBER", "SQL_E
XEC_START", "SQL_EXEC_ID", "PREV_SQL_ADD
R", "PREV_HASH_VALUE", "PREV_SQL_ID", "P
REV_CHILD_NUMBER", "PREV_EXEC_START", "P
REV_EXEC_ID", "PLSQL_ENTRY_OBJECT_ID", "
PLSQL_ENTRY_SUBPROGRAM_ID", "PLSQL_OBJEC
T_ID", "PLSQL_SUBPROGRAM_ID", "MODULE",
"MODULE_HASH", "ACTION", "ACTION_HASH",
"CLIENT_INFO", "FIXED_TABLE_SEQUENCE", "
ROW_WAIT_OBJ#", "ROW_WAIT_FILE#", "ROW_W
AIT_BLOCK#", "ROW_WAIT_ROW#", "TOP_LEVEL
_CALL#", "LOGON_TIME", "LAST_CALL_ET", "
PDML_ENABLED", "FAILOVER_TYPE", "FAILOVE
R_METHOD", "FAILED_OVER", "RESOURCE_CONS
UMER_GROUP", "PDML_STATUS", "PDDL_STATUS
", "PQ_STATUS", "CURRENT_QUEUE_DURATION"
, "CLIENT_IDENTIFIER", "BLOCKING_SESSION
_STATUS", "BLOCKING_INSTANCE", "BLOCKING
_SESSION", "FINAL_BLOCKING_SESSION_STATU
S", "FINAL_BLOCKING_INSTANCE", "FINAL_BL
OCKING_SESSION", "SEQ#", "EVENT#", "EVEN
T", "P1TEXT", "P1", "P1RAW", "P2TEXT", "
P2", "P2RAW", "P3TEXT", "P3", "P3RAW", "
WAIT_CLASS_ID", "WAIT_CLASS#", "WAIT_CLA
SS", "WAIT_TIME", "SECONDS_IN_WAIT", "ST
ATE", "WAIT_TIME_MICRO", "TIME_REMAINING
_MICRO", "TIME_SINCE_LAST_WAIT_MICRO", "
SERVICE_NAME", "SQL_TRACE", "SQL_TRACE_W
AITS", "SQL_TRACE_BINDS", "SQL_TRACE_PLA
N_STATS", "SESSION_EDITION_ID", "CREATOR
_ADDR", "CREATOR_SERIAL#", "ECID", "SQL_
TRANSLATION_PROFILE_ID", "PGA_TUNABLE_ME
M", "SHARD_DDL_STATUS", "CON_ID", "EXTER
NAL_NAME", "PLSQL_DEBUGGER_CONNECTED") A
S
select "SADDR","SID","SERIAL#","AUDSID","PADDR","USER#"
,"USERNAME","COMMAND","OWNERID","TADDR",
"LOCKWAIT","STATUS","SERVER","SCHEMA#","
SCHEMANAME","OSUSER","PROCESS","MACHINE"
,"PORT","TERMINAL","PROGRAM","TYPE","SQL
_ADDRESS","SQL_HASH_VALUE","SQL_ID","SQL
_CHILD_NUMBER","SQL_EXEC_START","SQL_EXE
C_ID","PREV_SQL_ADDR","PREV_HASH_VALUE",
"PREV_SQL_ID","PREV_CHILD_NUMBER","PREV_
EXEC_START","PREV_EXEC_ID","PLSQL_ENTRY_
OBJECT_ID","PLSQL_ENTRY_SUBPROGRAM_ID","
PLSQL_OBJECT_ID","PLSQL_SUBPROGRAM_ID","
MODULE","MODULE_HASH","ACTION","ACTION_H
ASH","CLIENT_INFO","FIXED_TABLE_SEQUENCE
","ROW_WAIT_OBJ#","ROW_WAIT_FILE#","ROW_
WAIT_BLOCK#","ROW_WAIT_ROW#","TOP_LEVEL_
CALL#","LOGON_TIME","LAST_CALL_ET","PDML
_ENABLED","FAILOVER_TYPE","FAILOVER_METH
OD","FAILED_OVER","RESOURCE_CONSUMER_GRO
UP","PDML_STATUS","PDDL_STATUS","PQ_STAT
US","CURRENT_QUEUE_DURATION","CLIENT_IDE
NTIFIER","BLOCKING_SESSION_STATUS","BLOC
KING_INSTANCE","BLOCKING_SESSION","FINAL
_BLOCKING_SESSION_STATUS","FINAL_BLOCKIN
G_INSTANCE","FINAL_BLOCKING_SESSION","SE
Q#","EVENT#","EVENT","P1TEXT","P1","P1RA
W","P2TEXT","P2","P2RAW","P3TEXT","P3","
P3RAW","WAIT_CLASS_ID","WAIT_CLASS#","WA
IT_CLASS","WAIT_TIME","SECONDS_IN_WAIT",
"STATE","WAIT_TIME_MICRO","TIME_REMAININ
G_MICRO","TIME_SINCE_LAST_WAIT_MICRO","S
ERVICE_NAME","SQL_TRACE","SQL_TRACE_WAIT
S","SQL_TRACE_BINDS","SQL_TRACE_PLAN_STA
TS","SESSION_EDITION_ID","CREATOR_ADDR",
"CREATOR_SERIAL#","ECID","SQL_TRANSLATIO
N_PROFILE_ID","PGA_TUNABLE_MEM","SHARD_D
DL_STATUS","CON_ID","EXTERNAL_NAME","PLS
QL_DEBUGGER_CONNECTED" from v$session
一会vsession,一会v_session,一会又是v
用eygle书中说的,概括一下,
"通常大部分用户访问的v视图是基于真正的v视图(这个试图是基于x
用代码模拟,
(1) 假设x$bisal是从dba_tables复制过来的,
create table x$bisal as select * from dba_tables;
(2) 创建视图vbisal,他的基表是xbisal,
create view vbisal as select * from xbisal;
(3) 创建视图v_bisal,他是基于vbisal视图创建的,
create view v_bisal as select * from vbisal;
(4) 创建公共同义词vbisal,他表示的是v_bisal视图,
create public synonym vbisal for v_bisal;
这说明了什么?说明用户常用的vbisal并不是真正的视图,他只是个同义词,相当于通过v_视图将真正底层v视图和普通用户进行了隔离,v_视图可以授权给用户,但是真正的v视图不能直接授权,这就是最开始,授权vsession提示错误的原因,按eygle所说,真正v
SQL> grant select on v$session to hr;
grant select on v$session to hr
*
ERROR at line 1:
ORA-02030: can only select from fixed tables/views
再者,之所以执行desc提示这个错误,就是因为用户对vsession同义词的检索会解析为对底层视图v_session的访问,真正v
SQL> desc v$session;
ERROR:
ORA-04043: object "SYS"."V_$SESSION" does not exist
了解了这些原因,我们知道如果让用户能访问vsession(同义词),需要授权的是他所代表的v_session视图,针对执行dbms_xplan的场景,不仅仅是上述提示的v
SQL> grant select on v_$sql_plan to hr;
Grant succeeded.
SQL> grant select on v_$session to hr;
Grant succeeded.
SQL> grant select on v_$sql_plan_statistics_all to hr;
Grant succeeded.
SQL> grant select on v_$sql to hr;
Grant succeeded.
Oracle的这种隔离保护基表的设计,确实值得学习,看似轻描淡写,实则内藏玄机。