不要乱动dual表

      今天在itpub上看到一个帖子,在删除表的时候出现问题:

SQL> drop table t4;
drop table t4
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01422: exact fetch returns more than requested number of rows

      通常来说 drop table 失败的原因都是权限不足,但这次却报递归SQL出错,咋看让人摸不着头脑,随着版主的分析终于揭开了这个谜底——动了 dual 表。

      以下是我的实验过程重演这个问题。

 

      首先以一个测试用户(我这里是scott)创建一个普通表:

scott@ora10g(oracle01) SQL> create table tab01(f01 int); 

Table created.

      以 sys 用户向 dual 插入一条数据,并提交:

sys@ora10g(oracle01) SQL> insert into dual values('Y');

1 row created.

sys@ora10g(oracle01) SQL> commit; 

Commit complete.

      由于一些内部的实现,以下是 dual 比较怪异的情况:

sys@ora10g(oracle01) SQL> select * from dual ; 

D
-
X

sys@ora10g(oracle01) SQL> select count(*) from dual  ;      

  COUNT(*)
----------
         1

sys@ora10g(oracle01) SQL> begin 
  2  for x in (select * from dual) loop
  3    dbms_output.put_line(x.dummy);
  4  end loop;
  5  end;
  6  /
X
Y

      可以看到只有匿名过程返回的结果才是两条数据。

      此时以scott用户删除之前创建的测试表 tab01,即可触发帖子里面的问题:

scott@ora10g(oracle01) SQL> drop table tab01 ; 
drop table tab01
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01422: exact fetch returns more than requested number of rows

      做一个级别为12的10046跟踪,尝试找出问题:

scott@ora10g(oracle01) SQL> alter session set tracefile_identifier='drop_table_error'; 

Session altered.

scott@ora10g(oracle01) SQL> alter session set events'10046 trace name context forever,level 12';

Session altered.

scott@ora10g(oracle01) SQL> drop table tab01 ; 
drop table tab01
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-01422: exact fetch returns more than requested number of rows

scott@ora10g(oracle01) SQL> alter session set events '10046 trace name context off';

      经过 tkprof 处理后,可以找到为一个引用了 dual 的地方:

select dummy 
from
 dual where  ora_dict_obj_type = 'TABLE'
......
......
Rows     Row Source Operation
-------  ---------------------------------------------------
      2  FILTER  (cr=212 pr=2 pw=0 time=32261 us)
      2   TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us)

       删除了 dual 表中“多余”行后却是:

select dummy 
from
 dual where  ora_dict_obj_type = 'TABLE'
......
......
Rows     Row Source Operation
-------  ---------------------------------------------------
      1  FILTER  (cr=107 pr=0 pw=0 time=17082 us)
      1   TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us)

      当然 drop table 也没有再出错了。

posted @ 2010-10-03 23:47  killkill  阅读(1198)  评论(3编辑  收藏  举报