其中rownum = 1查询在Oracle中占用时间

时间:2011-03-15 03:18:27

标签: oracle optimization where rownum

我正在尝试执行类似

的查询
select * from tableName where rownum=1

这个查询基本上是为了获取表的列名。表中有超过百万条记录。当我把上面的条件花了这么多时间来获取第一行时。是否有任何替代获取第一行。

6 个答案:

答案 0 :(得分:12)

这个问题已经得到解答,我将只提供一个解释,为什么有时过滤器ROWNUM = 1或ROWNUM <= 1可能会导致响应时间过长。

当遇到ROWNUM过滤器(在单个表上)时,优化器将生成一个带有COUNT STOPKEY的FULL SCAN。这意味着Oracle将开始读取行,直到遇到前N行(此处N = 1)。完整扫描从第一个范围读取块到高水位线。 Oracle无法确定哪些块包含行而哪些块没有预先确定,因此将读取所有块,直到找到N行为止。如果第一个块为空,则可能导致许多读取。

请考虑以下事项:

SQL> /* rows will take a lot of space because of the CHAR column */
SQL> create table example (id number, fill char(2000));

Table created

SQL> insert into example 
  2     select rownum, 'x' from all_objects where rownum <= 100000;

100000 rows inserted

SQL> commit;

Commit complete

SQL> delete from example where id <= 99000;

99000 rows deleted

SQL> set timing on
SQL> set autotrace traceonly
SQL> select * from example where rownum = 1;

Elapsed: 00:00:05.01

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=7 Card=1 Bytes=2015)    
   1    0   COUNT (STOPKEY)
   2    1     TABLE ACCESS (FULL) OF 'EXAMPLE' (TABLE) (Cost=7 Card=1588 [..])

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

正如您所看到的,一致获取的数量非常高(对于单行)。在某些情况下可能会遇到这种情况,例如,您插入带有/*+APPEND*/提示的行(因此高于高水位线),并且您还会定期删除最旧的行,从而导致开头有大量空白空间该部分。

答案 1 :(得分:4)

Oracle肯定有元数据表可以用来获取列名,比如DB2中的sysibm.syscolumns表吗?

而且,在quick web search之后,似乎就是这种情况:请参阅ALL_TAB_COLUMNS

我会使用那些而不是去实际的桌子,比如(未经测试):

SELECT   COLUMN_NAME
FROM     ALL_TAB_COLUMNS
WHERE    TABLE_NAME = "MYTABLE"
ORDER BY COLUMN_NAME;

如果你 一心想找出你的查询速度慢的原因,你应该恢复标准方法:让你的DBMS为你解释查询的执行计划。对于Oracle,请参阅this document的第9节。

Ask Tom - Oracle处有一个对话似乎暗示在选择阶段之后创建了行号,这可能意味着查询无论如何都要检索所有行。 explain可能有助于确定这一点。如果它包含FULL而不包含COUNT STOPKEY,那么这可以解释性能。

除此之外,我对Oracle细节的了解也在减少,您将不得不进一步分析explain

答案 2 :(得分:4)

试试这个:

select * from tableName where rownum<=1

有一些奇怪的ROWNUM错误,有时稍微改变查询会修复它。我以前见过这种情况,但我无法重现它。

以下是对类似问题的一些讨论:http://jonathanlewis.wordpress.com/2008/03/09/cursor_sharing/http://forums.oracle.com/forums/thread.jspa?threadID=946740&tstart=1

答案 3 :(得分:2)

您的查询正在进行全表扫描,然后返回第一行。

尝试

SELECT * FROM table WHERE primary_key = primary_key_value;

第一行,尤其是与ROWNUM相关的行,由Oracle任意决定。除非您提供ORDER BY子句,否则从查询到查询可能不一样。

因此,选择要过滤的主键值与获取单行的方法一样好。

答案 4 :(得分:1)

我认为你略微忽略了ROWNUM的概念 - 根据Oracle文档:“ROWNUM是一个伪列,它返回结果集中行的位置。在从数据库中选择记录后评估ROWNUM在执行ORDER BY子句之前。“ 所以它返回任何一行,它在结果集中考虑#1,在你的情况下将包含1M行。

您可能想要查看ROWID伪列:http://psoug.org/reference/pseudocols.html

答案 5 :(得分:0)

我最近遇到了你所描述的同样的问题:我希望从非常大的表中选择一行作为快速,脏,简单的内省,而“rownum = 1”单独表现得很差。以下是对我有用的补救措施。

选择某个索引的第一个项的max(),然后使用它选择“rownum = 1”的所有行的一小部分。假设我的表有一些关于数字“group-id”的索引,并比较一下:

 select * from my_table where rownum = 1;
 -- Elapsed: 00:00:23.69

用这个:

 select * from my_table where rownum = 1
    and group_id = (select max(group_id) from my_table);
 -- Elapsed: 00:00:00.01