Oracle中的DUAL表是很特殊的一张表,这种表只有一个字段,一条记录。Oracle很多查询的结果都通过访问这张表实现。所以很多包都依赖这张表。
由于这张表的特殊性,SQL语句的优化器进行了特殊的处理,比如在9i中:
| SQL> CONN /@YTK92 AS SYSDBA已连接。 SQL> SELECT * FROM DUAL; D - X SQL> INSERT INTO DUAL VALUES ('X'); 已创建 1 行。 SQL> SELECT * FROM DUAL; D - X SQL> SELECT COUNT(*) FROM DUAL; COUNT(*) ---------- 2 SQL> ROLLBACK; |
回退已完成。
| SQL> SELECT * FROM V$VERSION; BANNER ---------------------------------------------------------------- Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production PL/SQL Release 9.2.0.4.0 - Production CORE 9.2.0.3.0 Production TNS for 32-bit Windows: Version 9.2.0.4.0 - Production NLSRTL Version 9.2.0.4.0 - Production |
在9i的SQL优化器中,Oracle知道DUAL表只有一条记录,因此即使插入新的记录后,SELECT * FROM DUAL仍然返回一条记录。
而使用COUNT(*)的话,则会返回DUAL表中真正的记录数。
但是10g的SQL优化器进行了进一步调整,而且10g还增加了FAST DUAL这种执行计划,因此得到的结果和9i有了区别:
| SQL> CONN /@YTK102 AS SYSDBA已连接。 SQL> SELECT * FROM DUAL; D - X SQL> INSERT INTO DUAL VALUES ('X'); |
已创建 1 行。
| SQL> SELECT * FROM DUAL; D - X SQL> SELECT COUNT(*) FROM DUAL; COUNT(*) ---------- 1 SQL> SELECT * FROM V$VERSION; BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod PL/SQL Release 10.2.0.1.0 - Production CORE 10.2.0.1.0 Production TNS for 32-bit Windows: Version 10.2.0.1.0 - Production NLSRTL Version 10.2.0.1.0 - Production |
可以看到,10g的优化器中即使是COUNT(*)查询,返回的总数也是1。
也就是说,没有办法通过SQL获得DUAL表中真正的记录数。
虽然SQL中没有办法,但是PL/SQL是可以的,否则也不会导致EXPDP等操作报错了。
| SQL> BEGIN 2 FOR I IN (SELECT * FROM DUAL) LOOP 3 DBMS_OUTPUT.PUT_LINE(I.DUMMY); 4 END LOOP; 5 END; 6 / X X |
PL/SQL 过程已成功完成。
| SQL> ROLLBACK; |
回退已完成。
通过这个结果也可以看出,SQL优化器和PL/SQL优化器在处理DUAL表上的区别。

