sys.dual表被清空后引发的问题(2)

截取的Trace文件显示:
tsiz: 0x1fa0
hsiz: 0x16
pbl: 0x11085f05c
    76543210
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1f96
avsp=0x1f78
tosp=0x1f78
0xe:pti[0]      nrow=2  offs=0
0x12:pri[0]    offs=0x1f9b
0x14:pri[1]    offs=0x1f96
block_row_dump:
tab 0, row 0, @0x1f9b
tl: 5 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 1]  58                            <----原记录'X'
tab 0, row 1, @0x1f96
tl: 5 fb: --H-FL-- lb: 0x2  cc: 1
col  0: [ 1]  41                            <----新插入但未显示的记录'A'
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 929 maxblk 929

判断oracle应该在执行select * from dual的过程中过滤掉了多余的记录,始终保持只返回一条记录,有点类似在where条件里隐含添加了rowum<2,下面的一系列查询验证了这一点
SYS@tstdb1-SQL> select * from dual;

D
-
X

SYS@tstdb1-SQL> select * from dual where dummy='A';    <---加了"=A"条件后可以返回'A'

D
-
A

SYS@tstdb1-SQL> select * from dual where dummy in ('A','X');

D
-
X

SYS@tstdb1-SQL> select * from dual where dummy!='X';    <---加了"!='X'"条件后也可以返回'A'

D
-
A

SYS@tstdb1-SQL> select * from dual where dummy!='A';

D
-
X

此时我们再往dual表里插入一条记录
insert into dual values('B');
commit;

SYS@tstdb1-SQL> select * from dual;

D
-
X

SYS@tstdb1-SQL> select * from dual where dummy='A';

D
-
A

SYS@tstdb1-SQL> select * from dual where dummy='B';

D
-
B

SYS@tstdb1-SQL> select * from dual where dummy!='X';    <---始终返回现存的row number最小的记录

D
-
A

update dual set dummy='a' where dummy='A';
commit;

SYS@tstdb1-SQL> select * from dual where dummy!='X';  <---始终返回现存的row number小的记录

D
-
a

此时的block里存放了三条记录
block_row_dump:
tab 0, row 0, @0x1f9b
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 1]  58                            <---row 0:'X'
tab 0, row 1, @0x1f96
tl: 5 fb: --H-FL-- lb: 0x2  cc: 1
col  0: [ 1]  61                            <---row 1:'a'
tab 0, row 2, @0x1f91
tl: 5 fb: --H-FL-- lb: 0x1  cc: 1
col  0: [ 1]  42                            <---row 2:'B'
end_of_block_dump

删除"dummy='a'"这条记录
delete dual where dummy='a';
commit;

此时的block dump包含内容如下:
block_row_dump:
tab 0, row 0, @0x1f9b
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1        <---row 0 : 'X'
col  0: [ 1]  58
tab 0, row 1, @0x1f96
tl: 2 fb: --HDFL-- lb: 0x1                <---row 1 : 'a' 已标记为被删除
tab 0, row 2, @0x1f91
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 1]  42                                <---row 2 : 'B'
end_of_block_dump

SYS@tstdb1-SQL> select * from dual;

D
-
X

SYS@tstdb1-SQL> select * from dual where dummy!='X';          <---因为row 1的记录已经删除,所以返回了row 2:B

D
-
B

不加条件的删除,也是挑rownum较小的删
delete dual;
commit;

SYS@tstdb1-SQL> select * from dual;

D
-
B

在dual表只剩一条记录的情况下,千万不要再删了(虽然oracle不会阻止你删除最后一条记录),这样会引发本文开头所描述的各种问题
SYS@tstdb1-SQL> select * from dual where dummy!='B';

no rows selected

总结一下:
Dual表是Oracle自己维护的一张表,虽然是张普通表但是oracle对它有着一些特殊的处理:
对dual表进行insert、update操作后,不加条件的执行select * from dual只会返回其中的一条记录,且是其中rownum最小的记录;
对dual表不加条件的执行delete dual后会删除其中rownum较小的一条记录,如果表里只有一条记录,那么表就被清空了;
dual表用于sysdate等函数值的返回和一些内部视图访问时的递归调用,千万不要轻易的修改它,否则会产生意想不到的“效果”

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7d86c425f22f9eb95c67dd669911cfd4.html