在RAC环境中,查询一个视图出现了ORA-4063错误。
错误出现时的现象如下:
SQL> select * from v1;
select * from v1*第 1 行出现错误:
ORA-04063: view "U1.V1" 有错误
SQL> set long 1000
SQL> select text from user_views where view_name = 'V1';
TEXT
--------------------------------------------------------------------------------
select t1.id id1, t2.id id2
from t1, t2
where t1.id = t2.id
SQL> create or replace view v1 as2select t1.id id1, t2.id id23from t1, t24where t1.id = t2.id5;
视图已创建。
SQL> select * from v1;
未选定行
由于对视图的基表进行过重建的操作,因此很可能是这个原因导致了视图的错误。但是奇怪的是:为了获取视图错误的信息,而尝试重新创建视图时,错误却消失了。
Oracle对于ORA-4063错误的描述:
ORA-04063: %s has errors
Cause: Attempt to execute a stored procedure or use a view that has errors. For stored procedures, the problem could be syntax errors or references to other, non-existent procedures. For views, the problem could be a reference in the view’s defining query to a non-existent table. Can also be a table which has references to non-existent or inaccessible types.
Action: Fix the errors and/or create referenced objects as necessary
如果错误和Oracle文档中描述的一致,那么导致视图报错的原因就是视图所访问的表不存在,如果是这个错误的话那么没有道理可以通过重建视图来解决错误。
感觉是碰到了Oracle的bug,经过不断的尝试,最终重现了这个问题。
下面是问题重现的步骤:
SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
testrac2
SQL> create user u1 identified by u1 default tablespace users;
用户已创建。
SQL> create user u2 identified by u2 default tablespace users;
用户已创建。
SQL> grant create session, create view, create synonym to u1;
授权成功。
SQL> grant create session, create synonym to u2;
授权成功。
SQL> conn test/test已连接。
SQL> create table t1 (id number);
表已创建。
SQL> create table t2 (id number);
表已创建。
SQL> grant select on t1 to u1 with grant option;
授权成功。
SQL> grant select on t2 to u1 with grant option;
授权成功。
SQL> conn u1/u1已连接。
SQL> create synonym t1 for test.t1;
同义词已创建。
SQL> create synonym t2 for test.t2;
同义词已创建。
SQL> create view v1 as select t1.id id1, t2.id id22from t1, t23where t1.id = t2.id;
视图已创建。
SQL> create view v2 as select t1.id id1, t2.id id22from t1, t23where t1.id = t2.id;
视图已创建。
SQL> grant select on v1 to u2;
授权成功。
SQL> grant select on v2 to u2;
授权成功。
检查描述一下上面的测试步骤:在RAC环境的一个实例上,创建两个辅助用户,并给这两个辅助用户授权必要的权限。在TEST用户中建立两个基表,将基表的SELECT WITH GRANT OPTION权限授权给U1用户,U1用户建立同名同义词指向这两个基表,而后建立两个相同的视图访问这两个基表,并将这两个视图的查询权限授予用户U2。
SQL> conn u2/u2已连接。
SQL> select instance_name from v$instance;
INSTANCE_NAME
----------------
testrac1
SQL> create synonym v1 for u1.v1;
同义词已创建。
SQL> create synonym v2 for u1.v2;
同义词已创建。
SQL> select * from v1;
未选定行
SQL> select * from v2;
未选定行
在RAC的实例1上以U2用户建立连接并建立了同义词指向U1的视图,并通过同义词访问U1的视图。
下面回到实例2上,删除并重建TEST用户下的基表T1:
SQL> conn test/test已连接。
SQL> drop table t1 purge;
表已删除。
SQL> create table t1 (id number);
表已创建。
然后回到实例1上,使用U2用户查询V1视图:
SQL> select * from v1;
select * from v1*第 1 行出现错误:
ORA-04063: view "U1.V1" 有错误
这里报错是正常的,因为还没有给U1用户授权:
回到实例2,只给U1授权SELECT,U1拥有查询权限,但是U1不能将这个表的访问权限权限授予其他用户:
SQL> grant select on t1 to u1;
授权成功。
回到实例1,U2用户再次运行查询:
SQL> select * from v1;
select * from v1 *第 1 行出现错误:
ORA-04063: view "U1.V1" 有错误
还是相同的错误,但是问题已经产生了。因为对于单实例数据库而言,同样的操作应该报错ORA-3113,指出U2没有访问对象V1的权限,而不是出现ORA-4063错误。
回到实例2,检查U1用户下的视图状态:
SQL> conn u1/u1已连接。
SQL> select object_name, object_type, status 2 from user_objects 3 where object_name like 'V_';
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ------------------- -------
V1 VIEW INVALID
V2 VIEW INVALID
视图V1的状态是不正确的,如果是在单实例环境下进行测试,到这一步会发现V1的状态是VALID。因为U1已经有了访问T1的权限,而U2又尝试访问V1视图,在发现视图状态不正确后会尝试编译V1。虽然由于U1用户缺少SELECT WITH GRANT OPTION权限,使得U2用户没有权限访问V1视图,但是V1视图本身的编译不会报错。
切换到test用户,这次将GRANT权限也授权给U1用户:
SQL> conn test/test已连接。
SQL> grant select on t1 to u1 with grant option;
授权成功。
在实例1上,U2用户再次访问V1视图:
SQL> select * from v1;
select * from v1*第 1 行出现错误:
ORA-04063: view "U1.V1" 有错误
SQL> select * from v2;
未选定行
访问V1仍然报错,但是之前没有访问过的V2视图,在查询时没有报错。这时即使是U1本身去访问V1视图也会报错ORA-4063:
SQL> conn test/test已连接。
SQL> select * from v1;
select * from v1*第 1 行出现错误:
ORA-04063: view "U1.V1" 有错误
问题重现了。这个问题在RAC环境下才会出现,当授权操作和用户访问不再同一个实例上,由于Oracle的bug致使用户访问对象时没有检测到正确的权限,导致了视图状态的错误。
测试还发现造成BUG的几个必要条件:
U2用户在T1被删除后且还没有将权限授权给U1用户时,执行查询;
仅将T1的查询权限授权给U1,而没有授权WITH GRANT OPTION;
U2用户再次执行查询,且在授权和U2用户执行查询之间,U1用户没有执行过查询;
确保授权操作和U2查询操作处于RAC数据库的不同实例。
满足了这些条件,问题就可能会重现。
感觉问题产生的原因可能和下面两个BUG有一定的关系:
一次ORA-942错误的跟踪(一):http://yangtingkun.itpub.net/post/468/480559
一次ORA-942错误的跟踪(二):http://yangtingkun.itpub.net/post/468/480671
一次ORA-942错误的跟踪(三):http://yangtingkun.itpub.net/post/468/480744
一次ORA-942错误的跟踪(四):http://yangtingkun.itpub.net/post/468/480825
一次ORA-942错误的跟踪(五):http://yangtingkun.itpub.net/post/468/480896
RAC环境一个实例删除已被另一个实例删除的表时报错:http://yangtingkun.itpub.net/post/468/316777
问题解决倒是很简单,除了前面的重建视图外,重新编译视图也可以解决问题:
SQL> alter view v1 compile;
视图已变更。
SQL> select * from v1;
未选定行
根据上面的描述可以看到,这个bug出现的条件十分严格,在实际情况中碰到这个bug的可能性很小,而且解决起来也很容易。有人可能认为这个bug不用理会,但是对于一个DBA来说,应该搞清楚bug出现的原因以及这个bug的危害,如果不深入的分析怎么判断这个bug重现的可能性的大小以及bug对系统的影响呢。
没有人能解决所有碰到的问题,但是一个合格的DBA应该可以独立解决大部分碰到的问题。解决问题的能力并不是天生的,随着知识和经验的不断积累,解决问题的能力会不断的增强。知识积累可以通过学习文档获得,而经验的积累就需要在分析、解决问题的过程中获得。因此不要轻易放过任何一个问题,每个问题都是一个积累经验的机会。