Concepts-第6章翻译

6 对象之间的依赖关系

  一些对象包括视图和存储过程的定义中引用其他的对象,比如表。结果,被定义的这些对象依赖在它们定义中被引用的对象。这篇文章对象之间的依赖关系以及oracle是如何自动地跟踪和管理这些依赖关系。

 

该章包含下面的内容:

 *依赖问题的引入

 *对象之间依赖关系的解决

 *对象名字的解决

 *共享SQL语句中的依赖关系管理

 *本地和远程的依赖关系管理

 

依赖关系的引入

一些对象类型在它们的定义中引用了其他对象作为其定义的一部分。例如:一个视图通过一个查询语句来定义的,在这个查询语句中引用了表和其他的视图。一个存储过程的体会包含SQL语句,这些SQL语句中会引用数据库中的其他对象。在其定义中引用其他对象作为其定义的一部分的一个对象被称为依赖对象,同时被引用的对象是被引用对象。图6-1说明了依赖对象与被引用对象的不同类型:

6-1依赖以及被引用对象的可能的类型

如果修改被引用对象的定义,依赖对象可能或者不可能没有错误地继续运行,依赖于被变更的类型。例如:如果删除一张表,这样所有依赖于这张被删除的表的视图是不可用的。

 

Oracle自动地记录对象之间的依赖关系来减轻对于数据库管理员和用户的依赖关系管理的复杂的工作。例如:如果你修改一张表并且对于这张表几个存储过程都引用了它,oracle在存储过程下次被调用(运行或者反编译)时自动地会重新编译下对被修改的表有依赖关系的存储过程。

 

为了管理在对象之间的依赖关系,在数据库中的所有的对象有一个状态:

 *有效的对象已经被编译过并且当被引用时可以立即被使用;

 *无效的对象必须在它们被使用之前需要被编译下:

*对于存储过程,函数,以及包,这个编译意味着编译下这些对象;

*对于视图,这个编译意味着这个视图必须利用当前在数据字典中的定义重新解析下;

 只有依赖对象有可能是无效的状态。表,序列,以及同义词总是处于有效状态的;。

  如果一个视图,存储过程,函数,或者包是无效的,oracle可能会尽力编译下这些对象,但是与关联的对象的错误已经发生了。例如:当编译一个视图,这个视图的基表中的一个可能不存在了或者对于这个基表的正确的访问权力可能已经不存在了。当编译一个包时,会有PL/SQL或者SQL语法错误发生,或者被引用对象的访问权力可能也已经不存在了。带有这种问题的对象会保持无效状态。

 

Oracle在数据库中自动地跟踪详细的变化并且在数据字典中记录下被关联的对象的状态。

 

状态记录是一个反复的循环过程。被引用对象的状态的任何变化不仅仅会影响到直接的依赖对象的状态的改变,也会改变间接的依赖对象的状态。

 

例如:考虑直接引用视图的一个存储过程。在效果上,存储过程间接地引用那个视图的基表。因此,如果修改了基表,视图变为无效的状态,视图无效也导致存储过程变为无效。图6-2说明间接地依赖关系:

6-2 间接的依赖关系

 

对象之间的依赖关系的解决

当一个对象在SQL语句中直接地被引用或者通过引用依赖对象间接地被引用,oracle在必要的时候检查在SQL语句中明确指定的对象和任何被引用的对象的状态。Oracle的行为依赖于在SQL语句中直接或者间接被引用的对象的状态。

 *如果每个被引用的对象的是有效的,然后oracle不需要任何额外的工作就可以立即运行SQL语句;

 *如果任何被引用的视图或者PL/SQL程序单元(存储过程,函数,或者包)是无效的,然后oracle自动地试图来编译这个对象;

   *如果所有无效的被引用对象能够被成功地编译,然后它们被编译并且oracle运行SQL语句;

   *如果一个无效的对象不能够被编译成功,然后它保持无效状态。Oracle返回一个错误并且回滚这个失败的SQL语句。这个事务剩下的是照旧的并且能够被用户或者提交或者回滚。

   注意:只有在因为检查到对象无效但是还没被替换的情况下,oracle会动态地试图重新编译这个无效的对象。这个优化器消除了不必要的重新编译过程。

 

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

如果下面的条件满足则一个视图或者PL/SQL程序单元能够被编译并且使之有效:

 *视图或者程序单元的定义必须是正确的。所有的SQLP/SQL语句必须是正确的结构。

 *所有被引用的对象必须存在并且具有期待的结构。例如:如果一个视图的定义包含一列,那么这列必须在基表中是存在的。

 *视图或者程序单元的定义者必须拥有被引用对象的必要的权力。例如:如果在一个存储过程的SQL语句向一张表插入一条记录,那么这个存储过程的定义者必须有对这个饿被引用表的插入特权。

视图和基表

一个视图依赖在其定义的查询语句中所被引用的基表或者是视图。如果在定义试图的查询语句中没有明确哪些列被引用,例如:select * from table,然后在定义视图的那个时候定义视图的查询语句被存储在数据字典时被延伸了,包含了被引用基表的所有的列。

 

如果一个视图的基表或者视图被修改,重命名,或者删除了,然后这个视图变为无效的状态,但是在数据字典中该视图的定义以及其特权,同义词,其他的对象,以及其他引用该无效的视图的视图的信息仍然保存着。

注意:只要创建了表,索引,以及视图,然后删除这个表,所有依赖那张表的对象变为无效,包括视图,包,包体,函数以及存储过程。

 

任何试图想用无效的视图将自动地引起oracle动态地重新编译这个视图。在替换这个视图之后,这个视图可能变为有效或者无效的依赖于下面的条件:

 *定义视图的查询语句中所引用的所有基表必须存在。如果视图的一个基表被重命名或者删除,这个视图被变为无效并且不能被使用。引用这个无效视图的引用语句也会执行失败。如果这个基表由被重命名为原始的名字或者基表被重建,这个视图能够被编译成功。

 *如果基表被修改或者重新创建表并且新建的表和原来的表具有同样的列,但是这个基表的一列或者多列的类型已经被改变,然后最依赖的这张基表的视图能够被重新编译成功。

 *如果视图中的一个基表被修改或者重新创建表并且新建的表和原来的表至少具有同样的列集合,然后视图能够变为有效。如果基表用的列重新被创建,并且视图引用的列不再存在于这个重新创建的表中,这个视图将会变为无效。之后的要点在用select * from table定义的视图案例中是非常相关的,因为在视图定义的时刻定义的查询被扩展了并且永久地存储在数据字典中。

 

程序单元和被引用的对象

当被引用的对象定义被修改时,oracle自动地使程序单元无效。例如:假设一个单独的存储过程包含几个语句,这些语句中引用了表,视图,另一个单独的存储过程,已经公共的包中的存储过程。在这种情况下下面的条件必须控制:

 *如果被引用的表被修改,然后依赖的存储过程变为无效;

 *如果被引用试图的基表被修改,然后视图和依赖的存储过程变为无效;

 *如果被引用的单独的存储过程被替换,然后依赖的存储过程变为无效;

 *如果被引用的包的包体被替换,然后依赖的存储过程没有受影响。但是,如果被引用的包的包头被替换,然后依赖的存储过程变为无效。这个是通过包来减少存储过程和被引用对象之间的依赖关系的机制。

 *只要你创建一张表,索引以及视图,然后删除这个表,所有依赖那张表达饿对象变为无效,包括视图,包体,函数以及存储过程。

 

数据仓库需要考虑的事项

一些视图在晚上为了使加载的速度快点删除了表上的索引。但是所有依赖这个被删除索引的表的视图变为无效。这意味着紧接着任何引用这些无效的视图的包也变为无效。

 

为了使视图再一次有效,用下面的语句:

Select * from vtest;

或者

Alter view vtest compile;

 

连接状态和被引用的包

每个引用包结构的连接有它自己的那个包的实例,包括任何公共的和私有的变量,游标以及常量的持久的状态。如果一个连接的被实例化的包后来变为无效并且重新被编译,那么这个连接的包的包含状态的所有实例将丢失。

 

授权安全性

当一个DML对象或者系统特权从一个用户或者公共的权限中授予或者撤消并且自动地使定义者的所有依赖对象变为无效,Oracle会注意到。Oracle使依赖对象无效目的是为了核实一个依赖对象的定义者继续拥有所有被引用对象的必要的特权。内部地,oracle注意到这样的对象没有必要被重新编译。只是授权安全需要被验证,而不是任何对象的结构。优化器消除了不必要的重新编译过程并且防止了变更一个依赖对象的时间的需要。

 

对象名字的解决

SQL语句中被引用的对象的名字是由几个部分组成,由点隔开。下面描述了oracle如何解决对象名字。

1、  oracle试图限定在SQL语句中被引用的读下名字的第一部分。例如:在hr.employeehr是第一部分。如果名字只是由一个部分组成,那么这个部分就被认为是第一部分。

A、 在当前的用户下,oracle为找一个对象,该对象的名字匹配指定对象名字的第一部分。如果oracle没有找到这样的对象,然后继续步骤B

B、 Oracle继续寻找公共的同义词,同义词的名字与匹配指定名字的第一部分。如果没有找到,然后继续步骤C

C、 Oracle继续寻找用户,该用户的名字和指定的对象名字的第一部分匹配。如果找到,然后返回B步骤,现在用指定名字的第二部分作为对象来在匹配的用户下查找。如果第二部分在先前找到的用户下没有找到对应的对象或者根本就没有第二部分,然后oracle返回一个错误。

如果在C步骤中没有找到用户,然后对象也不能够被限定下来,然后oracle返回一个错误。

2、  一个用户对象已经被限定下来。指定的名字中的任何剩下的部分必须匹配一个被找到对象的有效部分。例如:如果hr.employees.department_id是一个名字,然后hr是限定为用户,employees限定为一张表,并且department_id必须对应于一列(因为employees是一张表)。如果employees限定为一个包名,然后department_id必对应于公共的常量,变量,那个包的存储过程,或者是那个包的函数。

对于一个对象依赖其他对象的不存在的情况是有可能的,因为oracle的解析引用的方式。这种情形发生在当依赖对象利用一个引用,这个引用可能被不同地解释为其他存在的对象。

 

共享SQL依赖关系的管理

除了管理用户内的对象之间的依赖关系,oracle也会管理在共享池中每个共享的SQL域中的依赖关系。如果表,视图,同义词,或者序列被创建,修改,或者删除,或者存储过程或者包头被重新编译,所有依赖共享的SQL域被变为无效。在紧接着的游标的执行,这个游标对应于无效的共享的SQL域,oracle将重新解析SQL语句来重新产生共享的SQL域。

 

本地和远程的依赖关系管理

跟踪依赖关系并且完成必要的重新编译被oracle自动地执行。本地依赖关系管理一般发生在一个单独的数据库中oracle管理对象之间饿依赖关系。例如:在同一数据库中一个存储过程中的SQL语句能够引用表对象。

 

远程依赖关系管理发生在当oracle通过网络来管理分布式环境的依赖关系。例如:一个oracle窗体的触发器能够依赖数据库中的对象。在分布式数据库中,本地的视图定义查询语句可以引用远程的表。

 

本地依赖关系的管理

Oracle管理所有本地的依赖关系是利用了数据库中内部的关系表,这个关系表一直跟踪每个对象的依赖对象。当一个被引用的对象被修改,oracle用依赖表来识别依赖对象,这个依赖对象然后被变为无效。

例如:假设一个存储过程update_all引用表JWARD.employees。如果这个表的定义以任何方式被修改过,则每个引用JWARD.employees表的对象的状态被变为无效,包括存储过程update_all。结果,这个存储过程是不能够被执行直到该存储过程被重新编译并且编译成功变为有效的。同样,当一个DML权力从一个用户中撤消掉,那么在这个用户下的每个依赖对象被设置为无效。但是,由于权限被撤消被变为无效状态的一个对象能够重新授权来使这个对象重新有效。,在这个过程中不需要完全的重新编译。

 

远程依赖关系的管理

Oracle也管理应用软件与数据库之间以及数据库与数据库之间的依赖关系。例如:oracle窗体应用可能包含一个引用一张表的触发器,或者在分布式系统中一个本地的存储过程可能调用远程的存储过程。数据库系统必须考虑这些对象之间的依赖关系。Oracle用不同的机制来管理远程的依赖,依赖相关的对象。

 

在本地与远程的数据库存储过程之间的依赖

存储过程之间的依赖包括在分布式数据库系统的函数,包,以及触发器,这些依赖关系通过timestamp checking方法和signature checking方法来管理。

动态的初始参数remote_dependencies_mode决定是timestamp checking方法还是signature checking方法来管理远程的依赖关系。

 

imestamp checking方法

imestamp checking依赖模式中,一个存储过程无论什么时候被编译或者被重新编译,它的时间(被创建,被修改以及被替换的时间点)都被记录在数据字典中。时间戳是一个记录,记录了这个存储过程被创建,或者修改,或者替换的时间。除此之外,存储过程的被编译版包含了关于该存储过程引用的每个远程存储过程的信息,包括远程存储过程的用户,包名,存储过程名以及时间戳。

 

当一个依赖存储过程被用时,oracle比较在编译时间记录的远程时间戳和远程地引用存储过程的当前时间戳。依据这个比较的结果,两种情况会发生:

 *如果时间戳是相等的,说明本地和远程的存储过程没有经过编译就执行了;

 *如果任何引用远程的存储过程的时间戳不匹配说明本地的存储过程是无效的,并且会返回一个错误给调用环境。此外,所有其他也是依赖该远程的存储过程的带有新时间戳的本地存储过程也被设置为无效。例如:假设几个本地的存储过程调用远程的存储过程,并且远程存储被重新编译。当本地存储过程中的一个被执行并且发现与远程的存储过程有不同的时间戳,则每个依赖远程存储过程的本地存储过程都被设置为无效。

 

实际的时间戳的比较是发生在本地存储过程的存储过程体中执行一个远程存储过程的时候。只有在这个时候通过分布式数据库的交流连接来比较他们的时间戳。因此,在本地存储过程中所有在调用无效存储过程之前的所有语句能够成功的执行,在一个无效存储过程调用之后的紧接着的语句根本不会执行。需要编辑。

 

依据无效的存储过程如何被调用,在无效的存储过程之前的DML语句被回滚,例如:在下面,当全部的PL/SQL块变化被回滚时update的结果也被回滚。

Begin

 

Update table set …

Invalid_proc;

Commit;

 

End;

但是,在下面,update结果起作用了,只有proc调用被回滚:

Update table set …

Execute invalid_proc;

Commit;

 

signature checking方法

oraclesignatures提供额外的远程依赖关系的管理能力。这个签名能力只影响远程的依赖。当在这种环境中重新编译总是会发生的情况下,本地的依赖不会受到影响。

 

存储过程的签名包含下面的明细信息:

 *包名,存储过程名或者函数名

 *参数的基本类型

 *参数的模式(in,outin out

  注:只有参数的类型和模式是重要的。参数的名字不影响签名。

 

如果签名依赖模式在被有效使用中,如果依赖单元包含一个对其父单元的存储过程的调用,并且这个存储过程的签名以不可兼容的方式被改变了,对远程程序单元的依赖导致依赖单元处于无效状态。一个程序单元可以是包,存储过程,函数或者触发器。

 

其他远程对象之间的依赖

Oracle除了管理本地和远程存储过程之间的依赖关系,但是不管理在远程对象之间的依赖。

例如:假设本地的视图是通过引用远程的表来被查询所创建和定义。也假设一个本地的存储过程包含的SQL语句中也引用了同样的远程的表。之后,远程的表被修改。

结果,尽管视图和或者存储过程在表被修改之后被用,并且尽管当视图和存储过程被用的时候返回错误,但是本地视图和存储过程也不被设置为无效。在这个例子中,视图和存储过程必须人工的被修改以便错误不再返回。在这样的例子中,对于不必要的依赖对象的重新编译来说采用依赖关系管理的缺乏是更可取的方法。

 

应用软件之间的依赖

在数据库应用软件中的代码可能会引用被连接的数据库中的对象。例如:OCI和预编译的应用软件可以提交自治的PL/SQL块。在oracle窗体应用软件中的触发器也会引用数据库对象。

这样的应用软件依赖于它们引用的数据库对象。根据开发环境的不同,依赖关系管理技术是多种多样的,

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值