设为首页 加入收藏

TOP

复盘eygle在甲骨文大会上演讲中的示例,看看什么是大师的由点及面(二)
2015-11-21 01:53:18 来源: 作者: 【 】 浏览:1
Tags:复盘 eygle 甲骨文 会上 演讲 示例 看看 什么 大师
10000 rows updated. Elapsed: 00:00:00.12

执行时间一下仅为0.12秒。

上面如果TBL_A的ID列设置为主键,则为1对1的连接,如果仅是TBL_B的ID列为唯一约束,则为1对N的连接。

?

总结:

通过两次优化,执行时间从7秒降到了0.12秒,虽然这里的示例数据未必和实际情况一致,但成比例的缩放足以说明这个问题,从这个案例可以看出,优化的本质就是少做事,原始SQL执行三次全表扫描,那目标就是减少全表扫描的次数,第一次优化的操作可能相对容易想到,但第二次优化的操作,就需要知道可以有这种语法,而且出现了ORA-01799的错误,还需要知道这种错误的根本原因是什么,才能有可行的解决方法。

?

问题还没完,以上说明了SQL语句的优化,下面就是针对这条SQL展开的知识。

假设上面的TBL_A和TBL_B表是属于用户bisal的,此时新建一个用户phibisal,并授予最简单的权限:

SQL> create user phibisal identified by phibisal;
User created.

SQL> grant create session to phibisal;
Grant succeeded.

bisal用户创建这两张表的public同义词:

SQL> create public synonym tbl_a for bisal.tbl_a;
Synonym created.

SQL> create public synonym tbl_b for bisal.tbl_b;
Synonym created.

然后授予phibisal用户对TBL_A表的读和更新权限:

SQL> grant select, update on tbl_a to phibisal;
Grant succeeded.

此时phibisal登录后执行:

sqlplus phibisal/phibisal

SQL> UPDATE (SELECT b.name b_name, b.class b_class, a.name, a.class
                      FROM tbl_a a, tbl_b b
                      WHERE a.id = b.id)
          SET name = b_name, class = b_class;
                FROM tbl_a a, tbl_b b
                                    *
ERROR at line 2:
ORA-00942: table or view does not exist

会提示TBL_B不存在,因为用户没有该表的任何权限,(注:此处和eygle的示例中反馈不同,他提示的是ORA-01031: insufficient privileges)
如果授予phibisal对TBL_B表的读权限,

SQL> grant select on tbl_b to phibisal;
Grant succeeded.

此时可以完成更新:

sqlplus phibisal/phibisal

SQL> UPDATE tbl_a a
          SET (name, class) = (SELECT name, class FROM tbl_b WHERE id = a.id)
          WHERE a.id IN (SELECT id FROM tbl_b b);
10000 rows updated.

但用如下SQL会提示权限错误:

UPDATE (SELECT b.name b_name, b.class b_class, a.name, a.class
                      FROM tbl_a a, tbl_b b
                      WHERE a.id = b.id)
          SET name = b_name, class = b_class;
                FROM tbl_a a, tbl_b b
                                    *
ERROR at line 2:
ORA-01031: insufficient privileges

即这种子查询更新会因没有TBL_B表的UPDATE权限报错。
但如果使用如下with语法,则可以正常执行:

SQL> UPDATE
(WITH tmp AS (
              SELECT b.name b_name, b.class b_class, a.name, a.class
              FROM tbl_a a, tbl_b b
              WHERE a.id = b.id)
             )
SET name = b_name, class = b_class;
10000 rows updated.

做得更彻底一些:

SQL> revoke update on tbl_a from phibisal;
Revoke succeeded.

撤消了phibisal用户对TBL_A的更新权限,按理说,phibisal用户不应该能再更新TBL_A表了。
使用上面两个调整后的SQL,确实如此:

sqlplus phibisal/phibisal

SQL> UPDATE (SELECT b.name b_name, b.class b_class, a.name, a.class
                      FROM tbl_a a, tbl_b b
                      WHERE a.id = b.id)
          SET name = b_name, class = b_class;
                FROM tbl_a a, tbl_b b
                                    *
ERROR at line 2:
ORA-01031: insufficient privileges     

SQL> UPDATE tbl_a a
          SET (name, class) = (SELECT name, class FROM tbl_b WHERE id = a.id)
          WHERE a.id IN (SELECT id FROM tbl_b b);
UPDATE tbl_a a
       *
ERROR at line 1:
ORA-01031: insufficient privileges

但是,奇怪的是如下SQL可以执行:

SQL> UPDATE
(WITH tmp AS (
              SELECT b.name b_name, b.class b_class, a.name, a.class
              FROM tbl_a a, tbl_b b
              WHERE a.id = b.id)
              SELECT * FROM tmp
             )
SET name = b_name, class = b_class;
10000 rows updated.

这就从原理规则上,违背了权限控制,看下版本:

SQL> select banner from v$version where rownum=1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

这就是2014年7月提出的一个bug,在11.2.0.3、11.2.0.4、12.1等版本中都存在的一个问题,需要修正这个bug,相当于使用with语法,可以绕过用户权限,对没有权限的表进行DML操作。

?

总结:

精髓不在于这个bug,而是在于从一条简单的UPDATE语句,可以派生出如此丰富的知识,可谓举一反三,受益匪浅。一方面需要我们能够从原理上理解每一个概念,另一方面也要培养自己举一反三,知识点由点及面的想法,做到真正的触类旁通,这样才能逐渐向大师靠拢,向大师学习。

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇去哪网实习总结:怎样配置数据库.. 下一篇《转》CentOS7安装MongoDB3.0服务..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: