oracle 对象失效(objects INVALID)

在日常数据库维护过程中,我们会发现数据库中一些对象(包Package、存储过程Procedure、函数Function、视图View、同义词…)会失效,呈现无效状态(INVALID)。

有时候需要定期检查数据库中存在哪些失效对象,对于存在异常的对象需要重新编译,有些自动失效的对象,一般会在下次调用的时候,会被重新编译,所以这些不需要人工干预。

那么为什么对象突然会失效呢?又如何快速、高效的编译失效对象呢?哪些失效的对象不需要我们去重新编译呢?

1 数据库对象失效原因

数据库对象失效的原因很多,下面大致归纳了一些常见的原因(有些漏掉的,希望大家补充):

1: 当被引用对象的结构变更时,都会使得相关的依赖对象转变为INVALID状态。(可创建view,更改表结构验证)

2:发布SQL脚本时(包、存储过程、函数等),没有充分测试,编译时出错,这时对象变为无效。

3: 数据库升级、迁移时,出现大量无效对象(本质原因,个人臆测归结为原因1)。

4: 诸如此类各种情况:例如,Oracle 会自动维护分区索引,对于全局索引,如果在对分区表操作时,没有指定update index,则会导致全局索引失效,需要重建。

2 编译失效对象的方法

统计失效的对象:

select owner, object_type, status, count(*)
from dba_objects
  where status='INVALID'
group by owner, object_type, status
order by owner, object_type

查看具体失效对象

col owner for a20;
col object_name for a32;
col object_type for a16
col status for a8
select owner, object_name, object_type, status
from dba_objects
where status='INVALID'
order by 1, 2,3;

3 Oracle中编译无效的对象常用方法

3.1 ALTER *** COMPLIE语句

手工进行编译,这个适用于少数、个别对象失效

alter package .<package_name> compile;
alter package .<package_name> compile body;
alter view .<view_name> compile;
alter trigger <schema).<trigger_name> compile;

3.2 sql脚本

@$ORACLE_HOME/rdbms/admin/utlrp.编译数据库失效对象。

许多情况下,由于数据库的升级或迁移,会导致数据库中的对象失效。由于对象之间可能存在复杂的倚赖关系,所以手工编译通常无法顺利通过。

通常我们会在Oracle的升级指导中看到这个脚本,Oracle强烈推荐在migration/upgrade/downgrade之后,通过运行此脚本编译失效对象。

但是注意,Oracle提醒,此脚本需要用SQLPLUS以SYSDBA身份运行,并且当时数据库中最好不要有活动事物或DDL操作,否则极容易导致死锁的出现(这是很容易理解的)。

3.3 自动编译的接口

ORACLE提供了自动编译的接口dbms_utility.compile_schema(user,false); 调用这个过程就会编译所有失效的过程、函数、触发器、包

exec dbms_utility.compile_schema( ‘SCOTT’ )

3.4 一些网友书写的编译失效对象

SQL 1: 编译失效对象

set heading off; 
set feedback off; 
set echo off; 
Set lines 999; 
 
Spool run_invalid.sql 
 
select 
'ALTER ' || OBJECT_TYPE || ' ' || 
OWNER || '.' || OBJECT_NAME || ' COMPILE;' 
from 
dba_objects 
where 
status = 'INVALID' 
and 
object_type in ('PACKAGE','FUNCTION','PROCEDURE','TRIGGER','JAVA SOURCE','JAVA CLASS','') 
; 
spool off; 
set heading on; 
set feedback on; 
set echo on; 
 
@run_invalid.sql  

SQL 2:在上面的方法中,只能知道某某编译失败,不清楚失败原因,可以用PL/SQL实现更详细的错误信息

DECLARE 
 v_objname        user_objects.object_name%TYPE; 
 v_objtype        user_objects.object_type%TYPE; 
 CURSOR cur IS 
    SELECT object_name,object_type 
      FROM USER_OBJECTS 
     WHERE status = 'INVALID' 
       AND object_type IN ('FUNCTION','JAVA SOURCE','JAVA CLASS','PROCEDURE','PACKAGE','TRIGGER'); 
BEGIN 
 OPEN cur; 
 LOOP 
    FETCH cur into v_objname, v_objtype; 
 
EXIT WHEN cur%NOTFOUND; 
    BEGIN 
      EXECUTE Immediate 'alter ' || v_objtype || ' ' || v_objname||' Compile'; 
      dbms_output.put_line('编译' || v_objtype || ' ' || v_objname || '()成功'); 
    EXCEPTION 
      WHEN OTHERS THEN 
        dbms_output.put_line('编译' || v_objtype ||' ' || v_objname || '()失败.' || SQLERRM); 
    END; 
 END LOOP; 
 CLOSE cur; 
END; 
<think>嗯,用户的问题是关于Oracle数据库中同义词被标记为无效(invalid)但仍然可以查询的原因及解决方法。我需要先回忆一下同义词在Oracle中的工作机制。 首先,同义词分为公有和私有,它们是指向其他对象(比如表、视图、函数等)的别名。当创建同义词时,系统会检查目标对象是否存在。如果目标对象被删除或结构发生改变,比如列被修改或删除,同义词的状态就会变成INVALID。但用户提到即使标记为无效,同义词仍然可以查询,这可能是因为虽然编译时检查到问题,但实际运行时如果权限足够,Oracle仍然会尝试解析。 接下来,可能的原因有几个。权限问题,比如用户有直接访问底层对象的权限,即使同义词无效,仍然可以通过直接访问来查询。另外,同义词的依赖关系可能没有及时更新,导致状态未正确反映。还有可能是延迟失效特性,Oracle可能不会立即将同义词标记为无效,而是在首次访问时检查。 解决方法方面,首先需要重新编译同义词,使用ALTER SYNONYM ... COMPILE命令。如果目标对象结构有变化,可能需要重建同义词。检查用户权限,确保同义词的拥有者有必要的权限。另外,使用数据字典视图如DBA_SYNONYMS来检查同义词的定义是否正确,目标对象是否存在。如果存在延迟失效的情况,可能需要手动干预重新编译或重建。 用户可能没有提到的是,有时候同义词无效可能是因为对象在不同模式下,或者存在同名的公共同义词覆盖了私有同义词。这也是需要检查的地方。另外,Oracle的版本不同可能会有不同的行为,需要确认版本是否有影响。 在生成相关问题的时候,需要涵盖权限管理、同义词失效的其他情况、如何监控同义词状态、依赖对象变更的影响,以及无效同义词对性能的影响。这些扩展问题能帮助用户更全面地理解问题。</think>### Oracle同义词显示无效但仍可查询的原因及解决方法 #### 一、根本原因分析 1. **对象依赖性变化** 当同义词指向的基表、视图或存储过程等底层对象发生结构变更(如列删除、表重命名)时,Oracle会将同义词标记为$STATUS = 'INVALID'$[^1],但已建立的会话可能继续使用原有解析缓存。 2. **权限穿透机制** 即使同义词标记为无效,若用户同时满足以下条件仍可访问: $$ \begin{cases} \text{直接访问权限:} & \text{用户具有基对象的直接SELECT权限} \\ \text{路径有效性:} & \text{基对象物理存在且可访问} \end{cases} $$ 3. **延迟失效特性** Oracle采用惰性失效验证机制,仅在首次访问时检查对象有效性,若此时基对象已恢复可用状态则继续操作。 #### 二、解决方案 ```sql -- 1. 重新编译同义词 ALTER SYNONYM schema.synonym_name COMPILE; -- 2. 验证基对象状态 SELECT owner, object_name, object_type, status FROM dba_objects WHERE object_name = 'BASE_OBJECT_NAME'; -- 3. 重建同义词(当基对象路径变更时) DROP SYNONYM schema.synonym_name; CREATE [PUBLIC] SYNONYM schema.synonym_name FOR schema.base_object@dblink; -- 4. 检查权限穿透问题 REVOKE SELECT ON base_table FROM public; GRANT SELECT ON base_table TO specific_role; ``` #### 三、验证流程图 $$ \begin{array}{ccc} \text{查询同义词} & \rightarrow & \text{检查VALID状态} \\ & \downarrow & \text{Yes} \rightarrow \text{正常访问} \\ & \text{No} & \\ & \downarrow & \\ \text{检查基对象存在性} & \rightarrow & \text{存在} \rightarrow \text{重建/编译} \\ & \downarrow & \\ \text{不存在} & \rightarrow & \text{对象恢复/路径修正} \end{array} $$ [^1]: 引用Oracle官方文档:当依赖对象发生结构性变更时,所有依赖对象会被标记为INVALID状态,但运行时可能通过权限穿透机制继续工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值