所有者权限
在Oracle中,系统权限、对象权限以及他们的集合角色权限,是一个相对复杂的安全体系。在前一篇《使用Role权限体系》(http://space.itpub.net/17203031/viewspace-691917)中,已经进行初步介绍。存储过程作为Schema对象下的程序单元,在进行Role处理时有一些特殊之处。今天我们继续介绍存储过程的权限体系:所有者权限和调用者权限。
在存储过程中,我们常常面对这样一个场景:用户A下有一个存储过程(或者函数体、包体)P,中间引用了对象X。在编译存储过程时,是要求用户A有对象X的权限的,如果没有,则系统报编译错误。当成功进行编译之后,用户A将执行execute存储过程P的权限赋给了用户B。但是用户B这时候不一定拥有X的使用权限,此时B能够成功执行存储过程P呢?我们通过一个简单实验,来证实一下。
实验环境准备
先准备用户test,除了具备基本的connect和resource角色权限之外,处于实验目的,赋给select any dictionary的系统权限给test。
SQL> connsys/sys@otstestas sysdba;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as SYS
SQL>
SQL> create user test
2 identified by test;
User created
SQL> grant resource to test;
Grant succeeded
SQL> grant connect to test;
Grant succeeded
SQL> grant select any dictionary to test;
Grant succeeded
Select any dictionary的系统权限意味着用户可以访问数据字典视图层面的视图对象数据,而且不会因为存储过程对角色权限的剥离效应而受到影响。
SQL> conn test/test@otstest;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as test
SQL> select count(*) fromdba_objects;
COUNT(*)
----------
53305
SQL> create or replace procedure p_test_nc
2 is
3 i number;
4 begin
5 select count(*)
6 into i
7 from dba_objects;
8
9 dbms_output.put_line(to_char(i));
10 end;
11 /
Procedure created
SQL> set serveroutput on size 1000;
SQL> exec p_test_nc;
53306
PL/SQL procedure successfully completed
可见,授予select any dictionary的用户test可以对dba_objects视图进行访问操作。同时,存储过程p_test_nc也可以顺利的编译执行。
实验一——所有者权限
准备好的实验环境,我们准备进行第一个项目实验。建立一个新用户ts,只有执行test用户下p_test_nc存储过程权限,但是没有访问dba_objects视图权限,看实际效果。
SQL> conn sys/sys@otstest as sysdba;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as SYS
SQL> create user ts
2 identified by ts;
User created
SQL> grant resource to ts;
Grant succeeded
SQL> grant connect to ts;
Grant succeeded
//用户ts只具有基本的连接和创建对象权限。
SQL> conn test/test@otstest;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as test
//将p_test_nc执行权限授权给ts
SQL> grant execute on p_test_nc to ts;
Grant succeeded
之后,我们检查ts用户下,p_test_nc的执行情况。
SQL> conn ts/ts@otstest;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as ts
SQL> select count(*) from dba_objects;
select count(*) from dba_objects
//ts用户没有dba_objects权限,显示访问必然没有结果;
ORA-00942:表或视图不存在
SQL> set serveroutput on size 1000;
SQL> exec test.p_test_nc;
53306
PL/SQL procedure successfully completed
结果显而易见,ts虽然没有访问dba_objects权限,但是因为拥有执行p_test_nc的权限,在执行p_test_nc的时候,也是可以在方法中访问到dba_objects。显然,此时ts在p_test_nc上借用了test用户对于dba_objects用户的权限,也就是对象所有者权限。
进一步证明我们的实验,可以进行些变化。
--当所有者权限失去时,即使调用者拥有权限也是无用的。
SQL> conn sys/sys@otstest as sysdba;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as SYS
//回收了test用户上的select any dictionary权限,此时test对dba_objects对象权限消失;
SQL> revoke select any dictionary from test;
Revoke succeeded
//赋予ts用户select any dictionary权限,这样ts就能访问dba_objects了;
SQL> grant select any dictionary to ts;
Grant succeeded
SQL> conn ts/ts@otstest;
Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0
Connected as ts
SQL> set serveroutput on size 1000;
SQL> select count(*) from dba_objects;//可以访问对象
COUNT(*)
----------
53306
SQL> exec test.p_test_nc;
begin test.p_test_nc; end;
ORA-06550:第1行,第12列:
PLS-00905:对象TEST.P_TEST_NC无效
ORA-06550:第1行,第7列:
PL/SQL: Statement ignored
我们看到了一些“诡异现象”,ts用户拥有dba_objects对象访问权限,同时也有执行p_test_nc的权限,但是执行的时候却报错,认为对象无效。
唯一的原因就是因为test用户失去了dba_objects对象的权限。而ts在调用p_test_nc时使用的是dba_objects的权限
进程属主--进程----日志位置
$LOG_HOME=$GRID_HOME/log/hostname/
root----/etc/init.d/init.ohasd run --- $LOG_HOME/ohasd.log
root ----- orarootagent.bin ------$LOG_HOME/agent/ohasd
root----------crsd.bin
grid------------oraagent.bin-----------$LOG_HOME/agent/crsd
grid------clusterd asm instance
grid---- tnslsnr (scan listener)
grid-----tnslsnr (node listener)
grid----- $GRID_HOME/opmn/bin/ons
grid ---- enhanced ONS
oracle----------oraagent.bin-----------同上
oracle --- 数据库实例
root------------orarootagent.bin
网络资源
scan virtual ip
node virtual ip
ASM cluster file system Registry
GNS
grid-----------diskmon.bin
root ---------- octssd.bin
grid---- oraagent.bin----------------$LOG_HOME/agent/ohasd
grid---------- evmd.bin
grid---------- evmlogger.bin
grid --------- gipcd.bin
grid --------- gpnpd.bin
grid --------- mdbsd.bin
root---- cssdmonitor
root ---- cssdagent------------------$LOG_HOME/agent/ohasd
grid --------- ocssd.bin
本文链接
今天收到一个同事的问题,有一段SQL跑了很久很久,根本没有结果,根据同事的反映,这个SQL一个月比一个月要慢。这是不被允许的事情,我们要做的就是对这个SQL进行一次优化。下面就是这次优化的记录。
首先说SQL:
t1.area_id,
t1.local_id,
count(distinct case
when t.type_id = '02' and t.valid_flag = 1 and
t3.trade_id = '1008601' then
t.user_id
else
null
end),
count(distinct case
when t.type_id = '02' and t.valid_flag = 1 and
t3.trade_id = '1008602' then
t.user_id
else
null
end)
from product_flag_m t,
... --省略部分都是类似上面的运算,很多,为了节省篇幅都取消了
left join VW_CODE_LOCALNET t1
on t.local_id = t1.root_local_id
LEFT JOIN TRADE_LIST T3
ON T.id2 = T3.id2
AND T3.trade_id IN ('1008601', '1008602')
where t.month_id = '201212'
group by t.month_id, t1.area_id, t1.local_id;
这段代码隐藏了敏感信息,可能会有一些修改的时候错漏的问题。
接下来就是比较老的套路了,查看这段SQL的执行计划:
这个时候可以初步判断是因为product_flag_m表太大造成的查询效率低下。既然只需要12月的数据,那么我自然而然的想到了将12月的分区压缩一下,利用压缩表的特点进行查询效率的提高。但是这是张生产表,不能随便操作,于是我就将12月份的type_id='02'的数据单独抽取出来形成一张新的表,当然这张表是压缩过的,而且我抽取的时候只抽取自己需要的字段,这样做的好处是尽量减少数据量,减轻数据库的负担。
下面就是使用了压缩表之后的执行计划:
可以看到COST是有所降低,但是这个和没有降低没什么区别。还是面临执行不出来的问题。
这个时候我注意到了ID=2的这一部执行计划。在id=3的hash join right outer之后,不管是COST还是BYTES都是在一个比较正常的水平之内的,那么问题就应该出在TRADE_LIST这个表上。
这个表是一张编码表,本身并不大,但是注意这里:
上图所示应该就是罪魁了。于是我想到了,既然最后需要过滤一下trade_id,那么为什么不直接就用一张只有trade_id为1008601和1008602的表呢?
于是我鬼使神差的建立了一张视图,这个视图就是只取了上面说的那么多数据,然后替换掉原来的SQL中的TRADE_LIST,删除了其中的
AND T3.trade_id IN ('1008601', '1008602') 语句,再看执行计划:
这个效果就非常好了。
我本身很担心这个视图用了以后会影响查询结果集。于是我自己造了一张表做了一个小测试。test3中有object_id为2, 3, 4, 5, 6, 7的记录,编码表中只有id为2, 3, 4, 5, 6的编码记录,SQL如下:
from test3 t1
left join test4 t2
on t1.object_id = t2.id
and t2.id in (2, 3);
这个结果有48行。制造一个视图:
然后替换成视图:
from test3 t1
left join test5 t2
on t1.object_id = t2.id;
结果还是48行。也就是说这个方法是可行的。
这样的话,如果在原来的SQL上加上并行提示,效果会更好。经过我的实际测试,3分钟以内就跑出了所有的结果。
或许会有人问我,为什么不加上索引?我并不是反对加索引,我不习惯使用索引的习惯是因为我们的现实环境所限,