【问题标题】:Does Oracle fetch all rows before applying the filter in the where clause? [duplicate]Oracle 在 where 子句中应用过滤器之前是否获取所有行? [复制]
【发布时间】:2012-11-27 20:17:36
【问题描述】:

可能重复:
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 实际是如何进行 fetch 的?

【问题讨论】:

  • 执行计划很可能会告诉你。
  • 如果 Oracle 不对此进行优化并获取 100k 行,我希望我的钱回来。
  • @user964970,我非常怀疑是否有人曾亲自为 Oracle 许可证付费:-)。
  • 对于那些投票结束的人,我不相信这是重复的。在“重复”线程中,有一个显式的rownum = 1 谓词,优化器可以使用它在第一行之后停止处理。在这种情况下,没有显式的 rownum 谓词,因此不会调用停止键优化。

标签: sql oracle oracle10g oracle11g rownum


【解决方案1】:

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

不过,很容易通过查看查询计划来了解何时应用过滤器。我将建立一个简单的表FOO 100,000 行

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.

现在,启用自动跟踪,禁止显示实际数据并运行查询

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

如果您查看查询计划,您可以看到我们在应用 rn between 1 and 100 谓词之前对 FOO 进行了全表扫描。所以整个结果集就物化了(一致get的个数大致就是表中block的个数)。

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

【讨论】:

    猜你喜欢
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    相关资源
    最近更新 更多