神奇的DUAL表总结 2013-04-25 10:47:24

分类: Oracle


★★★★★★★★★★★本文档版权归个人所有,未经允许,禁止用于商业用途,违者必究★★★★★★★★★★★

背景介绍:Oracle DUAL是一个很神奇的东西,为什么说它神奇呢?DUAL表属于SYS用户,SYS用户是专门管理Oracle数据字典的用户,DUAL表因此属于数据字典的一个组成部分(而且DUAL表是个特殊实现的数据字典表)。一个Oracle使用人员应该知道SYS里的东西只能查询,不可乱做修改的,否则会造成意想不到的、甚至毁灭性的灾难。既然DUAL表属于数据字典,归SYS用户管理,那么其他的用户是如何访问的呢?答案是通过一个叫DUAL的PUBLIC SYNONYM来访问的。


DUAL表是建立数据库的时候随数据字典创建而建立的,它是单行单列的一个表,一般称为“哑表、虚表等”,列名DUMMY,类型VARCHAR2(1),值为'X',为什么叫虚表,因为它有比物理表更多神奇内涵。这就是DUAL表的全部基本内容,对于这个基本内容要确保是固定的,不可修改,有很多莫名的问题产生就是因为动了这张表。DUAL表的基本内容虽然简单,但背后隐藏了很多神奇的内容,在下面的内容中会详细介绍。


DUAL表的主要作用是什么呢?有Oracle使用经验的都知道,我们常使用DUAL表来计算常量型表达式,比如用DUAL表访问,SELECT里可以是1、USER、SYSDATE、'abc'、TRUNC(SYSDATE,'DD')、SEQ.NEXTVAL等这些常量型表达式。因为DUAL表就一行,用于计算就很方便了,当然可能有人会问,DUAL表计算方便,那么我建立一个只有一行的表(多行当然经常不是我们需要的结果),不照样计算方便吗?那是的,当然计算方便,但是DUAL表和Oracle优化器有着更紧密的关联,优化器知道DUAL表只有一行,而且很特殊,还有一些优化访问手段,优化器遇到一些计算使用的是DUAL或只有一行的普通表,那么优化器的反应很可能是不同的,DUAL表的效率要优于那个普通表。另外DUAL表常用于结合CONNECT BY子句进行数据构造。


DUAL表是数据字典表,不能乱动,不可对它进行任何DDL、DML等操作,否则会造成意想不到的效果,比如给DUAL插入一条数据,那么执行DROP TABLE命令可能会报错,这些都在后面详细讲解,因为它很特殊,你只可对DUAL表使用SELECT权限,其他权限一律禁止。


内容简介:

1) DUAL表常规用途。

主要介绍DUAL表有哪些主要用途,比如计算,构造数据等。

2) DUAL表神秘之处

介绍在9i和10g下对DUAL进行DDL和DML操作的神奇表现、10g的FAST DUAL优化、在9i和10g下使用DUAL和CONNECT BY构造数据的一些问题和方法探讨以及其他DUAL神秘之处。

3) PL/SQL中使用DUAL赋值和直接变量赋值的性能区别。

通过测试说明SELECT ..INTO .. FROM DUAL与variable := value的性能区别。

4) 误删DUAL表的恢复过程。

误删DUAL表的相关方法介绍。

说明:本章内容脚本请参考dual_sample.sql,未做说明一律在当前版本的SQL*PLUS下完成脚本测试,未做说明所有脚本都是在下列版本下执行的:


DINGJUN123>show rel

release 1002000100

DUAL表的常规用途

DUAL是单行单列的,这个很特殊,我们常使用它来获取一些常量型值或做一些计算功能,当然DUAL还有个重要的作用就是用于数据构造。下面举例说明下DUAL表的常见功能。


1)获取一些系统函数的值

这个用的最多的就是获取SYSDATE函数的值,从而返回当前时间了,此外还可以获取USER等函数值。如:


DINGJUN123>SELECT SYSDATE FROM DUAL;


SYSDATE

--------------

20-10月-10


已选择 1 行。


DINGJUN123>SELECT USER FROM DUAL;


USER

---------------

DINGJUN123


已选择 1 行。


2)做相关运算

比如用DUAL做些数学运算,一些函数测试,获取sequence等。如:


--数学运算,充当计算器

DINGJUN123>SELECT 2*5-10 num FROM DUAL;


NUM

----------

0


已选择 1 行。


--函数测试,有时候一函数搞不清楚用法,用DUAL测试很方便

DINGJUN123>SELECT REPLACE('abcdefg','f','$') rp FROM DUAL;


RP

--------------

abcde$g


已选择 1 行。


--查找序列,序列是必须要通过SQL来查找的,所以用DUAL很简单,如果用一个多行的物理表,会有递增的序列出现

DINGJUN123>SELECT seq.nextval FROM DUAL;


NEXTVAL

----------

301


已选择 1 行。


--用普通物理表,有多少行,就会计算多少次,一般我们不需要这种功能

DINGJUN123>SELECT COUNT(*) FROM t;


COUNT(*)

----------

2


已选择 1 行。


DINGJUN123>SELECT seq.nextval FROM t;


NEXTVAL

----------

302

303


已选择2行。


3)使用DUAL表构造数据

使用DUAL表构造数据,常结合CONNECT BY层次查询来构造,比如现在要构造1到100之间所有偶数,如下:


DINGJUN123>SELECT LEVEL lv

2 FROM DUAL

3 WHERE MOD(LEVEL,2) = 0 --注意WHERE是在CONNECT BY之后执行的,过滤CONNECT BY的结果

4 CONNECT BY LEVEL <= 100;


LV

-------------------

2

4

6

---中间结果省略

96

98

100


已选择50行。


上面用DUAL和CONNECT BY实现常见的数据构造,注意这是在10g下完成的,如果是9i不一定成功,而且9i的不同版本还有不同的表现,这个会在下一节详细讲解


再来看一个例子,有时候,我们需要建立些简单的表来进行测试,那当然需要给表插入些测试数据了,使用DUAL表,可以很简单地构造些测试数据:


DINGJUN123>DROP TABLE emp_t;


表已删除。


DINGJUN123>CREATE TABLE emp_t

2 AS

3 SELECT 1 id,'liming' name, DATE'2010-10-20' hire_date FROM DUAL UNION ALL

4 SELECT 1 ,'jack',DATE'2010-10-21' FROM DUAL;


表已创建。


使用DUAL表很简单吧,用于测试,构造些数据(还可以与DBMS_RANDOM包配合构造随机数据),的确很方便,当然有很多方法可以实现数据的构造,比如数据直接放csv文件里,通过sql*loader来导入,或用外部表,也可以通过plsql developer等工具提供的快速导入功能(比如select * from table for update然后粘贴),但是少量数据还是用DUAL简单,它可以保存测试的脚本。下面做一个比较复杂点的DUAL表构造随机测试数据:

DUAL表的神秘之处

DUAL表是Oracle中特殊的数据字典表,它是由Oracle内部代码维护的,我们一般情况下看到的DUAL表单行单列,字段名为DUMMY,类型VARCHAR2(1),这些都是表象,因为DUAL表在Oracle中的用途很广泛,使用很便利,所以Oracle考虑了多方面因素,才造了这么个神奇的“虚表”。你认为DUAL表真的是单行单列的吗?先看表象:


SYS>desc dual

名称 是否为空? 类型

---------- -------- --------------

DUMMY VARCHAR2(1)


SYS>select * from dual;


DU

--

x


已选择 1 行。


表面来看,的确是单行单列,TOM(TOM KYTE,Oracle VP,世界知名数据库专家)曾经说DUAL表之所以做成单行单列只是为了便利,当然DUAL表有更多的用途,比如一些系统操作,如DROP TABLE,一些系统包等都可能会用到DUAL表,你改变了DUAL表的属性,比如增强一行,那么可能会导致严重的问题,数据字典都是不能乱动的。DUAL表的数据类型和列名以及它的值并没有绝对的关系,这个要注意,DUAL表用途广泛,Oracle优化器看到DUAL表,它就知道DUAL表应该是单行单列的,而且会启用相关优化措施(这点会在后面的例子中有说明)。那么DUAL表真的是单行单列的吗?看TOM给的一点提示:


--关闭数据库后,神奇的DUAL不同了

SYS>alter database close;


数据库已更改。


SYS>desc dual

名称 是否为空? 类型

---------- -------- --------------

DUMMY VARCHAR2(1)


SYS>select * from dual;


ADDR INDX INST_ID DU

-------- ---------- ---------- -- ---------- ------

03674AD4 0 1 X


已选择 1 行。


DUAL表既然是属于SYS数据字典,那么普通用户怎么访问到DUAL呢,而且还不要加SCHEMA,那当然是利用PUBLIC同义词了,查看:


SYS> SELECT * FROM DBA_SYNONYMS WHERE TABLE_NAME='DUAL';


OWNER SYNONYM_NAME TABLE_OWNER TABLE_NAME DB_LINK

-----------------------------------------------------------------------

PUBLIC DUAL SYS DUAL


已选择 1 行。


从上面可以看到,DUAL表并没有那么简单。它拥有很多让你amazing的特性,当然如果你动了它,它会让你更加地amazing。下面就开始DUAL表的探秘之旅吧。


1)在9i、10g下对DUAL进行DDL、DML操作的神奇表现

前面已经说了,DUAL表这种特殊的数据字典,你只可以使用同义词来进行查询操作(当然所有的数据字典都不应该乱动),而不能进行其他的操作改变DUAL表的基本属性,如果DUAL表属性一旦发生变化,可能会造成很多意想不到的问题,下面就暴力改变下DUAL表的属性,看看DUAL表到底有哪些神奇之处(切记,不要在生产环境下实验,后果自负)。


先在9i下进行相关实验(增加插入一行,然后SELECT 'X' FROM DUAL看看有几行,增加游标迭代):


--select * from dual和select dummy from dual在9i和10g下的表现一样,这个不用测试了

SQL>SHOW REL

release 902000400


SQL> select * from dual;


D

-

X


1 row selected.


--给DUAL表插入一行

SQL> insert into dual values('Y');


1 row created.


--查看全部DUAL表内容,so amazing,竟然只返回新插入的一行

SQL> select * from dual;


D

-

Y


1 row selected.


--用count查看全部记录数量,正确返回,与上面的对比,DUAL表在SQL*PLUS里的表现真是很让人迷惑

SQL> select count(*) from dual;


COUNT(*)

----------

2


1 row selected.


SQL> commit;


Commit complete.


已经演示了一些DUAL表的神奇表现,下面神奇继续上演:


--全部清空,再次amazing,明明两行,竟然只删除了一行后插入的,当然和上面的select不谋而合

SQL> delete from dual;


1 row deleted.


SQL> select * from dual;


D

-

X


1 row selected.


--继续删除,这下清净了

SQL> delete from dual;


1 row deleted.


SQL> select * from dual;


no rows selected


SQL> select count(*) from dual;


COUNT(*)

----------

0


1 row selected.


--不能乱删的,恢复吧

SQL> insert into dual values('X');


1 row created.


SQL> select * from dual;


D

-

X


1 row selected.


--我已经不相信select * from dual了,还是count一下保险点,正确

SQL> select count(*) from dual;


COUNT(*)

----------

1


1 row selected.


--对上面的演示继续,这次不用delete from dual了,用delete from dual where dummy='Y',直接删除掉即可

SQL> insert into dual values('Y');


1 row created.


SQL> commit;


Commit complete.


SQL> select count(*) from dual;


COUNT(*)

----------

2


1 row selected.


SQL> delete from dual where dummy='Y';


1 row deleted.


SQL> commit;


Commit complete.


SQL> select count(*) from dual;


COUNT(*)

----------

1


1 row selected.


--TRUNCATE和UPDATE没有什么神奇的

--TRUNCATE操作,和DELETE FROM不同,TRUNCATE在9.2.4下能清楚全部DUAL数据

--到10g版本测试,TRUNCATE,UPDATE,DELETE FROM表现和9i一样,但是也有不一样的,请见10g版本测试

SQL> insert into dual values('Y');


1 row created.


SQL> commit;


Commit complete.


SQL> truncate table dual;


Table truncated.


SQL> select * from dual;


no rows selected


SQL> select count(*) from dual;


COUNT(*)

----------

0


--恢复,执行UPDATE,可以改变其值

SQL> insert into dual values('X');


1 row created.

Commit complete


SQL> update dual set dummy='Y';


1 row updated


SQL> commit;


Commit complete


SQL> select * from dual;


DUMMY

-----

Y


--恢复

SQL> update dual set dummy='X';


1 row updated


SQL> commit;


Commit complete


上面演示了在9.2.4下对DUAL的INSERT,DELETE,TRUNCATE,UPDATE操作,可以看出,DUAL表的确很神奇,当然在SQL*PLUS里新插入一上用SELECT * FROM DUAL是看不出到底有几行的,用COUNT函数可以,在测试中,我发现在PLSQL DEVELOPER工具中用SELECT * FROM DUAL是可以看出到底有多少行的,说明SQL*PLUS和DUAL还是紧密相关的。


DUAL表多插入了或清空了,那么有什么不利之处呢?不利之处太多了,可能使系统包失效,使一些DDL操作报错,使一些程序报错等。下面就继续在9.2.4下,用简单的存储过程测试下DUAL表多插入了或清空了导致的问题。


SQL> select * from dual;


D

-

X


已选择 1 行。


已用时间: 00: 00: 00.03

SQL> insert into dual values('Y');


已创建 1 行。


已用时间: 00: 00: 00.07

SQL> commit;













以上测试只是9.2.0.4的情况,下面回到本章10g版本,你会发现与9.2.0.4很多不同的地方。


SQL>show rel

release 1002000100

SQL>select * from dual;


DU

--

X


已选择 1 行。


SQL>insert into dual values('Y');


已创建 1 行。


SQL>commit;


提交完成。


SQL>select * from dual;


DU

--

Y


已选择 1 行。


--注意和9i测试的对比,10.2就算插入了一行记录,count(*)仍然不能正确显示行数,还是1行,9i的为2

SQL>select count(*) from dual;


COUNT(*)

----------

1


已选择 1 行。


--这个在9i显示的是两行,但是10.21行,可以猜测10.2多插入了行,在PL/SQL里的select sysdate into .. from dual

--也不会出问题,这个应该属于10g的优化

SQL>select sysdate from dual;


SYSDATE

--------------

31-10月-10


已选择 1 行。


--从上面可以看出,多插入一行,对select xxx into variable from dual是没有影响的。这个在9i下是要报too_many_rows错误--

DINGJUN123>declare

2 var_date date;

3 begin

4 select sysdate into var_date from dual;

5 dbms_output.put_line(var_date);

6 end;

7 /

31-10月-10


PL/SQL 过程已成功完成。


--DELETE FROM 9i一样,只能删除一行

SQL>delete from dual;


已删除 1 行。


SQL>commit;


提交完成。


SQL>select * from dual;


DU

--

X


已选择 1 行。


SQL>delete from dual;


已删除 1 行。


SQL>commit;


提交完成。


--DUAL表全清空了,COUNT还是只显示1行,DUAL表除了select * from dualselect dummy from dual无行显示外,--计算是正常的1

--这个和上面的多插入类似,9i也不同

SQL>select count(*) from dual;


COUNT(*)

----------

1


已选择 1 行。


SQL>select * from dual;


未选定行


SYS>select dummy from dual;


未选定行


SQL>select sysdate from dual;


SYSDATE

--------------

31-10月-10


已选择 1 行。


--DUAL表没有数据了同样不影响select xxx into variable from dual9i下测试是报no_data_found异常的

DINGJUN123>declare

2 var_date date;

3 begin

4 select sysdate into var_date from dual;

5 dbms_output.put_line(var_date);

6 end;

7 /

31-10月-10


PL/SQL 过程已成功完成。


--TRUNCATE正常截断,和9i一样,当然和上面一样,空DUAL表的COUNT和相关计算不受影响

SQL>insert into dual values('X');


已创建 1 行。


SQL>insert into dual values('Y');


已创建 1 行。


SQL>commit;


提交完成。


SQL>truncate table dual;


表被截断。


SQL>select * from dual;


未选定行


--恢复

SQL>insert into dual values('X');


已创建 1 行。


SQL>commit;


提交完成。


下面看看10g多插入表对一些DROP TABLE操作的影响,当然其他的也可能影响(比如DROP TABLESPACE),没有测试而已,测试的目的是说明,DUAL表不可欺。


--多插入一条数据语句省略

DINGJUN123>drop table t;

drop table t

*

第 1 行出现错误:

ORA-00604: 递归 SQL 级别 1 出现错误

ORA-01422: 实际返回的行数超出请求的行数



返回ORA-00604和ORA-01422错误,当对表进行DROP的时候,看到这两个错误,就要想起是DUAL表里的数据多了的缘故。通过SQL TRACE可以看到:


select dummy

from

dual where ora_dict_obj_type = 'TABLE'


说明DUAL表和DROP TABLE操作密切相关,此外DROP TABLESPACE也类似,当然可能有其他的操作也相关,这里不测试了。


9i好检查DUAL表数据是不是多了,一个COUNT搞定,在10g下测试COUNT还是返回一条,那么怎么办呢?有很多方式可以看到DUAL表的真正记录数,如到PLSQL DEVELOPER工具下查看,或用PL/SQL的游标解决。如下:


1)PL/SQL DEVELOPER可以正确显示10g下的DUAL表记录数

uid-7655508-id-3619896.html


2)采用游标迭代

为什么不直接在PL/SQL里select sysdate into..等方式查看呢?前面测试了,10g下的DUAL不管是数据多了还是数据少了,select sysdate into … from dual显示的都是1行,而select dummy into … from dual如果清空了则不返回数据,多了的话也只显示1行,所以用迭代的方式。


DINGJUN123>select count(*) from dual;


COUNT(*)

----------

1


已选择 1 行。


DINGJUN123>set serveroutput on


DINGJUN123>begin

for rec in (select dummy from dual) loop

3 dbms_output.put_line(rec.dummy);

4 end loop;

5 end;

6 /

X

Y


PL/SQL 过程已成功完成。


通过测试9i和10g相应版本的DUAL操作,可以看出,9i到10g变化还是挺大的,9i下多插入或清空了DUAL表数据影响SELECT COUNT(*) FROM DUAL以及类似于SELECT SYSDATE FROM DUAL之类的操作,多插入了不影响DROP TABLE等操作。但是在10.2的测试下可以看出,多插入或清空不影响上述COUNT和计算操作,但是多插入了,则影响DROP TABLE等操作(清空了不影响DROP TABLE操作),当然清空了影响SELECT * FROM DUAL或SELECT DUMMY FROM DUAL,但是不影响类似于SELECT SYSDATE FROM DUAL。此外,10g下在PL/SQL里用隐式游标迭代查找DUAL表里的数据,和9i表现一样。


3)10g的FAST DUAL优化


9i下的DUAL表访问没有优化,一般逻辑读为3。10g的DUAL表如果不需要访问DUAL表里的内容,而是利用DUAL表的一些功能,比如select sysdate from dual,则会采用FAST DUAL方式来访问表,它不是真正的访问表,因此逻辑读为0,这样在一个高频DUAL表使用的系统中,会大量减少逻辑读。

9i下DUAL的访问方式是:


--不管是只访问dual表本身的内容,还是用于计算等,都是全表扫描DUAL表,返回逻辑读一般为3个,无FAST DUAL

SQL> set autotrace traceonly

SQL> select * from dual;


Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'DUAL'


Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

3 consistent gets

0 physical reads

0 redo size

487 bytes sent via SQL*Net to client

655 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


SQL> select sysdate from dual;


Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (FULL) OF 'DUAL'


Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

3 consistent gets

0 physical reads

0 redo size

495 bytes sent via SQL*Net to client

655 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


10g则不同,如果只是利用DUAL表查找比如SYSDATE,做些相关计算,比如1+1,那么Oracle优化器(CBO,RBO一样规则)采用FAST DUAL方式访问,它不需要真正访问DUAL表,因此逻辑读为0。


DINGJUN123>set autotrace traceonly

--访问DUAL表本身的数据,不能走FAST DUAL,因为它需要真正访问表了

DINGJUN123>select * from dual

2 ;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 272002086


--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |

| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |

--------------------------------------------------------------------------



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

3 consistent gets

0 physical reads

0 redo size

409 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


--用于取系统函数,计算,启用FAST DUAL,不需要真正访问表,逻辑读为0

DINGJUN123>select sysdate from dual;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 1388734953


-----------------------------------------------------------------

| Id | Operation | Name | Rows | Cost (%CPU)| Time |

-----------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |

| 1 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |

-----------------------------------------------------------------



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

0 consistent gets

0 physical reads

0 redo size

417 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


--这个也是访问了DUAL表

DINGJUN123>select dummy,sysdate from dual;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 272002086


--------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |

| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |

--------------------------------------------------------------------------



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

3 consistent gets

0 physical reads

0 redo size

474 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed



--RBO虽然不用了,还是测试一下,规则与CBO一样

DINGJUN123>alter session set optimizer_mode=rule;


会话已更改。


DINGJUN123>select 1 from dual;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 1388734953


---------------------------------

| Id | Operation | Name |

---------------------------------

| 0 | SELECT STATEMENT | |

| 1 | FAST DUAL | |

---------------------------------


Note

-----

- rule based optimizer used (consider using cbo)



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

0 consistent gets

0 physical reads

0 redo size

406 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


DINGJUN123>select sysdate,sysdate,sysdate from dual;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 1388734953


---------------------------------

| Id | Operation | Name |

---------------------------------

| 0 | SELECT STATEMENT | |

| 1 | FAST DUAL | |

---------------------------------


Note

-----

- rule based optimizer used (consider using cbo)



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

0 consistent gets

0 physical reads

0 redo size

547 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed


DINGJUN123>select dummy from dual;


已选择 1 行。



执行计划

----------------------------------------------------------

Plan hash value: 272002086


----------------------------------

| Id | Operation | Name |

----------------------------------

| 0 | SELECT STATEMENT | |

| 1 | TABLE ACCESS FULL| DUAL |

----------------------------------


Note

-----

- rule based optimizer used (consider using cbo)



统计信息

----------------------------------------------------------

1 recursive calls

0 db block gets

3 consistent gets

0 physical reads

0 redo size

409 bytes sent via SQL*Net to client

384 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

10g有了FAST DUAL优化,增强了DUAL表作为常用工具的功能,这也是Oracle10g新版本带来的众多新特性之一,值得注意。