在where子句中应用过滤器之前,Oracle是否会获取所有行?

时间:2012-11-27 20:17:37

标签: sql oracle oracle10g oracle11g rownum

  

可能重复:
  Does Oracle fetch all the rows before evaluating rownum?

如果我在具有100k行的表上运行以下查询

select * from 
(
 select rownum rownumber, fname, lastname
 from customers
) where rownumber between 1 and 100;

Oracle是否获取所有100k,然后过滤获取的行列表以获得前100个,或者它是否有一种巧妙的过滤方式,前100个而不是获取所有100k行?

有没有办法在上面的例子中找出Oracle实际上如何进行提取?

1 个答案:

答案 0 :(得分:3)

首先,由于您的内部查询没有进行任何排序,因此查询返回任意100行。如果这是尝试构建查询以遍历结果,那么这不是正确的方法,因为它不高效且因为它不正确 - 返回的行集可能会随着时间的推移而变化,行可能会很容易出现在结果的许多不同页面上或根本没有页面。

但是,通过查看查询计划来查看何时应用过滤器是很容易的。我将构建一个包含100,000行的简单表FOO

SQL> drop table foo;

Table dropped.

SQL> create table foo
  2  as
  3  select level col1
  4    from dual
  5   connect by level <= 100000;

Table created.

现在,启用autotrace,禁止显示实际数据并运行查询

SQL> set autotrace traceonly;

SQL> select *
  2    from (select rownum rn, col1
  3            from foo)
  4   where rn between 1 and 100;

100 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3193632835

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |   101K|  2577K|    47   (3)| 00:00:01 |
|*  1 |  VIEW               |      |   101K|  2577K|    47   (3)| 00:00:01 |
|   2 |   COUNT             |      |       |       |            |          |
|   3 |    TABLE ACCESS FULL| FOO  |   101K|  1288K|    47   (3)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RN"<=100 AND "RN">=1)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        164  consistent gets
          0  physical reads
          0  redo size
       2504  bytes sent via SQL*Net to client
        590  bytes received via SQL*Net from client
          8  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        100  rows processed

如果您查看查询计划,可以看到我们在应用FOO谓词之前对rn between 1 and 100进行了全表扫描。因此整个结果集已实现(并且一致获取的数量大致是表中的块数)。

如果您使用了更合适的分页查询(例如,Tom Kyte有Oracle Magazine article on pagination和更长discussion of pagination on askTom),您会在查询计划中看到SORT ORDER BY STOPKEY这样的内容告诉你,Oracle知道它可以在某一点之后停止处理。