Dual表小议
Dual表是ORACLE里比较特殊的表,在很多时候都能看到它。例如,我们要取系统时间:
SQL> select sysdate from dual;
SYSDATE
-----------
2004-12-15
但Dual表到底是怎么回事,我倒是想仔细探究一番。恰好,某日CSDN社区ORACLE板块上,有网友把Dual表删了,这个更引起了我探究的兴趣。
先来看看系统里有多少对象是和Dual表有关的:
SQL> select OWNER,OBJECT_NAME,OBJECT_TYPE,TO_CHAR(CREATED,'YYYY-MM-DD')
CREATEDATE from all_objects where object_name like '%DUAL%';
OWNER OBJECT_NAME
OBJECT_TYPE CREATEDATE
------------------------------
------------------------------ ------------------
----------
SYS DUAL
TABLE 2000-02-27
PUBLIC
DUAL SYNONYM 2000-02-27
可以看到在系统中存在一个DUAL的表,还有一个DUAL的同义词。
DUAL表的所有者是SYS,因为,DUAL是系统创建的,而SYS是根用户。而所有者为PUBLIC的SYNONYM则让DUAL对所有用户都是透明的,不需要加“SYS”前缀。
再来看一下,DUAL表的结构:
create table SYS.DUAL
(
DUMMY
VARCHAR2(1)
)
tablespace SYSTEM
pctfree 10
pctused 40
initrans 1
maxtrans 255
storage
(
initial 16K
next
16K
minextents 1
maxextents 505
pctincrease 50
);
DUAL表中仅有1列:DUMMY,为VARCHAR2(1)型。(很是困惑,ORACLE为什么要用VARCHAR(1)型,用CHAR(1)难道不好么?)从这样的表结构来看,DUAL表设计的目的就是要尽可能的简单,以减少检索的开销。
还有,DUAL表是建立在SYSTEM表空间的,第一是因为DUAL表是SYS这个用户建的,本来默认的表空间就是SYSTEM;第二,把这个可能经常被查询的表和用户表分开来存放,对于系统性能的是有好处的。
有了创建了表、创建了同义词还是不够的。DUAL在SYS这个Schema下面,因此用别的用户登录是无法查询这个表的,因此还需要授权:
grant
select on SYS.DUAL to PUBLIC with grant option;
将Select 权限授予公众。
接下来看看DUAL表中的数据,事实上,DUAL表中的数据和ORACLE数据库环境有着十分重要的关系(ORACLE不会为此瘫痪,但是不少存储过程以及一些查询将无法被正确执行)。
SQL>
select * from dual;
DUMMY
-----
X
在创建数据库之后,DUAL表中便已经被插入了一条记录。个人认为:DUMMY字段的值并没有什么关系,重要的是DUAL表中的记录数。
下面,试着把DUAL表中的数据删除,看看会出现什么结果:
SQL>
delete from dual;
1 行 已删除
SQL> select * from dual;
DUMMY
-----
看起来很正常,那么来取一下系统时间来看看:
SQL> select sysdate from dual;
SYSDATE
-----------
这下子,我们便取不到系统日期了。因为,sysdate是个函数,作用于每一个数据行。现在没有数据了,自然就不可能取出系统日期。
这个对于很多用
select
sysdate into v_sysdate from
dual;
这种方式取系统时间以及其他信息的存储过程来说是致命的,因为,ORACLE会马上抛出一个NO_DATA_FOUND(ORA-01403)的异常,即使异常被捕获,存储过程也将无法正确完成要求的动作。
反过来,如果我们再插入一条数据,那会是什么结果呢?
SQL> insert into dual values('Y');
1 行 已插入
SQL> commit;
提交完成
SQL> select * from dual;
DUMMY
-----
X
Y
SQL> select sysdate from dual;
SYSDATE
-----------
2004-12-15
2004-12-15
这个时候返回的是两条记录,这样同样会引起问题。在通过使用
select sysdate into v_sysdate from dual;
来获取时间或者其他信息的存储过程来说,ORACLE会抛出TOO_MANY_ROWS(ORA-01422)异常。
因此,需要保证在DUAL表内有且仅有一条记录。当然,也不能把DUAL表的UPDATE,INSERT,DELETE权限随意释放出去,这样对于系统是很危险的。
最后,总结一下如果DUAL表被“不幸”删除后的恢复:
1. 以SYS登录。
2. 创建DUAL表(SQL如上述)。
3.
授予公众SELECT权限(SQL如上述,但不要给UPDATE,INSERT,DELETE权限)。
4. 向DUAL表插入一条记录(仅此一条):
insert into dual values('X');
5. 提交修改。
其他:
对于如此重要的表,ORACLE不予以保护确实令我想不通(针对8i),但是对于DELETE操作来说,ORACLE却似乎在后面做了些什么。
SQL>
select * from dual;
DUMMY
-----
X
Y
SQL> delete from dual;
1 行 已删除
SQL> commit;
提交完成
SQL> select * from dual;
DUMMY
-----
Y
不管表内有多少记录(没有记录除外),ORACLE对于每次DELETE操作都只删除了一条数据。这个又是为什么呢??
关于优化问题:
建立一个索引,可能是有用的,但是,如果能把DUAL表放入SGA是不是更好??可能不是,因为我们几乎从来都不关心DUMMY这个列是什么值(这次除外),ORACLE也不会关心的。
PS:
DUAL在英语里是双重的意思,取这个表名确实不好理解(可能是个人智商问题),DUMMY是虚的意思,这个倒是好理解,就当它没有吧…………
欢迎大家指教!
阅读(960) | 评论(0) | 转发(0) |