截取的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等函数值的返回和一些内部视图访问时的递归调用,千万不要轻易的修改它,否则会产生意想不到的“效果”