分享

Oracle concepts 学习笔记(4)——Schema对象间的依赖关系

 昵称16441188 2014-05-29

Schema对象间的依赖关系

一些对象的定义,包括视图和存储过程,需要引用其它的对象,比如表。因此,这些对象的定义将依赖于被引用的对象的定义。

一、简单介绍依赖

   一些类型的schema对象可以引用其它对象作为自己定义的一部分。比如,视图就是基于引用表或者其它视图的查询而得到的。Procedure的内容也可以包括一个sql语句来引用数据库的其它对象。一个对象引用其它对象作为它定义的一部分,称这个对象为依赖对象。而被引用的那个对象称作引用对象。下图列举了可能作为依赖对象和引用对象的schema 对象类型。如果修改一个引用对象的定义,依赖对象可能或者不可能继续工作,取决于修改的类型。例如,drop一个表,那么基于这个表的所有视图将会变成unusable。

Oracle会自动记录对象间的依赖关系。从而减轻这个复杂的依赖工作对DBA和用户的痛苦。例如,如果修改一个被多个存储过程引用的表,oracle会自动重新编译这个依赖的存储过程,在这个过程下次被引用的时候(重新执行或者重新编译)。【问题1:是重新编译这些直接依赖于表的存储过程,还是修改间接依赖于表的存储过程,即依赖于存储过程的过程?】

为了管理schema对象间的依赖关系,在数据库中所有的schema对象都有一个status。

     有效的schema对象已经被编译,并且可以被引用者立即使用。

     无效的schema对象在使用前必须编译。

     对于procedures、functions和packages,这就意味着编译这些schema对象。

     对于views,这就意味着需要使用数据字典中当前的定义来再次解析这些views。

仅仅依赖对象可以无效。Tables、sequences和synonyms一般是有效的。

如果一个视图、过程、函数或者包是无效的,oracle可能会尝试着去编译它,但是与这些对象相关的错误可能会遇到。例如,当你编译一个视图,而构成该视图的一个基表不存在或者基于基表的正确权限没有,此时会报错。当编译一个包,可能有一个PL/SQL或者SQL语句错误,也可能涉及引用对象的正确权限不存在,就会报一些错误。在这些情况下的schema对象将保持无效。

Oracle自动跟踪数据库的详细变更,并在数据字典中记录涉及到的对象的适当的状态。状态记录是以一个递归处理。任何在引用对象的状态改变不仅仅会影响到直接依赖对象,而且也会影响到间接的依赖对象。例如,存储过程引用一个视图。实际上存储过程间接依赖视图的基表。因此,如果修改这个基表,视图将无效,同时这个过程也会变成无效。

二、对象依赖的决心

当一个对象被sql语句直接引用或者间接通过一个依赖对象来引用,oracle有必要明确的检查sql语句和引用对象中对象的状态。Oracle的动作取决于直接或间接引用在sql语句中对象的状态:

如果所有引用对象都是有效的,这时oracle会无需其它额外工作来帮助,立即执行sql语句。

如果任何引用视图或者过程(包括函数或者包)是无效的,这时oracle自动尝试去编译这个对象。

如果所有的无效对象能够成功编译,这时它们被编译,oracle运行这个sql语句。

如果有一个无效对象不能成功编译,这时该对象仍然保持无效。Oracle会返回一个错误并且回滚包含在这个sql语句中的事务。

   提示:oracle动态地尝试重新编译一个无效对象,仅仅是在该对象没有被replaced的情况下,并检测到其状态为无效。这样就可以最优地减少没有必要的重新编译。

三、视图和PL/SQL程序单元的编译:

一个视图或者PL/SQL程序单元可以被编译并且变成有效,如果满足以下情况的话:

视图或者PL/SQL程序单元的定义是是正确的。所有sql和PL/SQL语句必须是正常的构造。

所有引用的对象必须存在并且是期望的结构。例如,如果定义一个视图包括基表的一列,则该列必须在基表中。

视图或者PL/SQL程序单元的拥有者必须对引用对象有必要的权限。例如,一个过程中的sql语句向表中插入记录,则该过程的拥有者必须有向引用表插入的权限。

视图和基表:

一个视图是在查询中依赖基表或者其它的视图。如果定义视图的查询没有清楚地指出所引用的列,例如 select * from table,这时定义查询会根据存储在数据字典中包含该基表所有的列来展开这个查询。如果视图的基表或者视图被altered、rename或者dropped,这时视图是无效的,但是它的定义同权限、同义词和其它对象,和其它引用该视图的无效视图仍然一起保存在数据字典中。

提示:无论什么时候,创建一个表、索引和视图,然后drop这个索引,所有依赖该表的对象是无效的,包括视图、包、包体、函数和过程。【回头有专门的测试案例】

一个尝试使用无效视图的动作都会让oracle自动重新动态编译这个视图。当replace这个视图之后,该视图是有效或者无效,取决于以下的环境:

      所有视图引用的基表必须存在。如果基表改名或者dropped,则视图将无效并且不可用。引用无效视图会使引用语句失败。该视图可以编译仅仅在基表名被修改回来或者基表重建。

      如果基表原样修改或者重建,但是基表的一个或者多个列的数据类型被修改,这时任何依赖的视图能够重新编译成功。

      如果基表使用最少的同样列来修改或者重建,这时视图将是有效的。如果基表使用新列和视图引用的列不在来重建表中,这时视图无效。后一点尤其会发生在使用select * from table 查询来构造的视图中。因为定义的查询在视图创建时根据数据字典中存储的基表列的信息来展开。

四、程序单元和引用对象

当程序单元所引用对象的定义发生修改时,oracle自动使改程序单元无效。例如,假定一个standalone过程包含多个语句,其中引用到表、视图、另外一个standalone过程和一个public package procedure。在这种情况下,以下条件控制:

      如果引用的表发生altered,这时依赖procedure将变成无效。

       如果视图的基表发生altered,则视图和依赖的procedure无效。

      如果standalone过程被replaced,这时依赖procedure无效。

     如果引用的package的body被replaced,这时依赖procedure不受影响。然而,如果引用包的specification【包头】被replaced,这时依赖程序无效。这是一种最小化在procedure和引用对象中使用包的依赖。

      无论何时创建一个表、索引和视图,然后drop这个索引,则所有引用该表的对象将变成无效。包括视图、包、包体和函数和procedures。【将有专门的测试验证】。

五、数据仓库的考虑:

一些数据仓库在晚上来drop表上的索引来加速数据加载。然而,所有引用该表的视图,由于索引的drop将会变成无效。这也就意味着随后运行的任何引用视图的包将会变成无效。一定要记住:无论何时创建一个表、索引和视图,然后drop这个索引,则所有引用该表的对象将变成无效。包括视图、包、包体和函数和procedures。为了使视图再次有效,可以使用以下任一语句:

      select * from vtest;

      alter view vtest compile;

会话状态和引用的包:

    Each session that references a package construct has its own instance of that package, including a persistent state of any public and private variables, cursors, and constants. All of a session’s package instantiations including state can be lost if any of the session’s instantiated packages are subsequently invalidated and recompiled。【不太明白意思,记录下来?】

六、安全授权:

    当一个DML对象或者系统权限被授予或者回收从一个用户或者public,自动将拥有者的所有依赖对象的无效。Oracle利用将依赖对象无效来验证依赖对象的拥有者是否继续有对所引用对象的必要权限。

七、函数索引的依赖:

函数索引依赖于定义索引的表达式上所使用的函数。如果一个PL/SQL或者包中函数被修改,这时该索引被标识为disabled。

创建函数索引的条件:

     以下的初始化参数必须被定义:

query_rewrite_integrity 的值必须为trusted。

query_rewrite_enabled的值必须为true。

compatible必须是8.1.0.0.0或者以上的值。

     该用户必须有create index、query rewrite 或者create any index和global query rewrite的权限。

为了使用一个函数索引:

       索引创建后,表必须被分析。

      查询保证使用索引表达式得到一个null值,因为null值不会存储在索引中。

确定性函数:

任何用户书写的函数将使用在索引上必须用DETERMINISTIC来定义,声明该函数经常返回相同的输出,为不同的输入。

定义函数的权限:

索引的owner需要在用来定义函数索引的函数上拥有execute权限。如果execute权限被收回,oracle将标记这个索引disabled。索引的拥有者不需要在函数上拥有execute with grant option权限来授予潜在表上select权限。

解决基于函数索引的依赖:

一个函数索引依赖所使用的函数。如果函数或者包含函数的包的包头被重新定义(或者索引的owner的execute权限被回收),这时以下情况会出现:

      索引被标识为disabled。

       查询一个disabled索引会报错,如果优化器选择使用索引的话。

      在disabled索引的DML操作将会fail,除非索引已经被标识为unusable并且初始化参数skip_unusable_indexes被设置为true。

   为了修改函数后使索引重新生效,使用alter index ... enable语句。

八、对象名称确定:

   引用在sql语句中的对象名称可以由几部分构成,有【.】好分割。以下将描述oracle如何解决对象名称:

1.       oracle尝试锁定sql语句中引用对象名称的第一部分。例如,在hr.employees 中hr就是第一部分,如果仅仅只有这一部分,这时这部分是认为是第一部分。

a)在当前schema下,oracle搜索与第一部分相同的的对象名,如果不能找到,继续执行b步。

b)oracle搜索名称与第一部分相同的公用synonym。如果找不到,继续执行c步。

c)oracle搜索名称与第一部分相同的schema。如果找到,这时返回执行a步【原文是b步,有问题】,不过现在使用第二部分在匹配的schema下搜索与第二部分同名的对象,如果没有找到,或者根本就没有第二部分,此时oracle会返回一个错误。

如果没有schema在c步找到,则该对象不会被有效并且oracle返回一个错误。

2.       一个schema对象被有资格【qualified】。名称任何剩下的部分必须是找到对象的一个有效部分。例如,如果hr.employees.department_id是一个name,这时hr被qualified是一个schema,employees被qualified是一个表,则department_id必须是employees表中相应的一列。如果employees被qualified一个package,这时department_id必须对应成包中的一个公用constant、variable、procedure或者function。

九、共享sql的依赖管理:

   除了管理schema对象间的依赖,oracle同样需要管理共享池中每个共享sql区域的依赖。如果一个表、视图、同义词或者序列被创建、修改或者drop或者一个procedure或包头被重现编译,所有依赖共享sql区域将变成无效。在随后一个游标执行时,不会重用原来的解析信息,oracle重新解析sql语句并重现产生共享sql区域。

十、本地和远程依赖管理:

跟踪依赖和完成必要的重新编译是由oracle自动执行的。本地依赖管理发生在当oracle管理同一个数据库中的对象时。例如,procedure引用同数据库中的表。远程依赖管理发生在oracle通过网络管理分布式数据库中的依赖。在分布式数据库中,一个本地视图可以引用一个远程的表。

本地依赖的管理:

Oracle使用数据库内部的依赖表来管理本地依赖。该表跟踪记录每个schema对象的依赖对象。当一个引用对象发生修改时,oracle使用depends-on来识别依赖对象,此时将其置为无效。例如,假定一个名称就做update_sal的存储过程引用jward.employees表。如果该表定义发生任何修改,则引用jward.employees的每个对象的状态都会改变为无效。当然也包括update_sal的存储过程。同样,当一个DML权限从一个用户处回收,则每个引用该用户的依赖对象将变成无效。然而,一个对象的无效是因为权限的回收而造成的可以通过再次授权而是对象重新有效,在这种情况向不需要完全重新编译。

    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多