Oracle EXISTS子句Vs ROWNUM = 1

时间:2013-10-01 20:52:29

标签: sql oracle

很长一段时间以来,我一直在使用EXISTS子句来确定给定条件中给定表中是否至少存在一条记录。 例如 - 如果我想查看“employee”表中是否存在lastname ='smith'的员工,我使用了以下查询

select 1
  into v_exists_flag
  from dual
 where exists (select 1 
                 from employee 
                where lastname = 'smith'
              )

这肯定比使用count(*)子句更有效。

select count(*) 
  into v_count 
  from employee
 where lastname = 'smith'

如果v_count> 0然后......

但是,最近有人提到使用ROWNUM = 1比使用EXISTS子句有更好的性能,如下所示

select 1
  into v_count
  from employee
 where lastname = 'smith'
   and rownum = 1

这是对的吗?有人可以证实这一点。

提前致谢

2 个答案:

答案 0 :(得分:3)

在启用自动跟踪的情况下尝试两个选项,并查看哪些一致性越少。我认为他们都会表现相同,但对我来说,rownum示例更容易阅读。

例如:

SQL> create table t1 as select object_name from all_objects;

Table created.

SQL> create index t1_idx1 on t1 (object_name);

Index created.

SQL> set autot on

SQL> select 1 from t1 where object_name = 'TOP_N' and rownum = 1;

     1
----------
     1
Statistics
----------------------------------------------------------
  0  recursive calls
  0  db block gets
  2  consistent gets
  0  physical reads
  0  redo size
519  bytes sent via SQL*Net to client
523  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 1 from dual where exists (select object_name from t1 where object_name = 'TOP_N'); 

     1
----------
     1

Statistics
----------------------------------------------------------
  0  recursive calls
  0  db block gets
  2  consistent gets
  0  physical reads
  0  redo size
519  bytes sent via SQL*Net to client
523  bytes received via SQL*Net from client
  2  SQL*Net roundtrips to/from client
  0  sorts (memory)
  0  sorts (disk)
  1  rows processed

答案 1 :(得分:1)

stackoverflow上有类似的问题。

Adam Musch在此声明没有真正的区别: The fastest way to check if some records in a database table?

这是关于rownum = 1性能的另一个主题: Under what conditions does ROWNUM=1 significantly increase performance in an "exists" syle query

但是,我在未编制索引的表上尝试了两种方法,并且EXISTS方法的成本略高:

ROWNUM approach plan EXISTS approach plan 显然,更高的计划是由于需要额外的DUAL呼叫。

示例:

CREATE TABLE rownum_test (x)
  AS SELECT rownum FROM all_objects;

DECLARE
  v_exists NUMBER;
BEGIN
  FOR v_i IN 1..34050 LOOP
    SELECT 1
      INTO v_exists
      FROM dual
    WHERE EXISTS (SELECT 1 FROM rownum_test WHERE x = v_i);
  END LOOP;
END; -- 13,2 seconds

DECLARE
  v_exists NUMBER;
BEGIN
  FOR v_i IN 1..34050 LOOP
    SELECT 1
      INTO v_exists
      FROM rownum_test
    WHERE x = v_i AND rownum = 1;
  END LOOP;
END; -- 13,3 seconds

另一方面,测试显示ROWNUM方法略慢 - 但可能是我的简单测试数据不够好。

在Oracle 11G R2上​​进行测试。