2

我正在尝试执行类似的查询

select * from tableName where rownum=1

这个查询基本上是为了获取表的列名。表中有超过一百万条记录。当我提出上述条件时,它需要花费很多时间来获取第一行。是否有任何替代方法来获取第一行。

4

6 回答 6

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*/提示的行(因此高于高水位线),并且您还定期删除最旧的行,导致段开头有很多空白空间。

于 2011-03-15T13:12:33.217 回答
4

当然,Oracle 有可以用来获取列名的元数据表,比如sysibm.syscolumnsDB2 中的表?

而且,在快速的网络搜索之后,情况似乎就是这样:见ALL_TAB_COLUMNS

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

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

如果您一心想找出查询缓慢的原因,您应该恢复到标准方法:让您的 DBMS 为您解释查询的执行计划。对于 Oracle,请参阅本文档的第 9 节。

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

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

于 2011-03-15T03:22:08.300 回答
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

于 2011-03-15T04:52:30.567 回答
2

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

尝试

SELECT * FROM table WHERE primary_key = primary_key_value;

第一行,特别是与 ROWNUM 相关的行,是由 Oracle 任意决定的。除非您提供 ORDER BY 子句,否则查询之间的情况可能不同。

因此,选择一个主键值作为过滤依据是一种获得单行的方法。

于 2011-03-15T03:43:23.977 回答
1

我认为您稍微错过了 ROWNUM 的概念 - 根据 Oracle 文档:“ROWNUM 是一个伪列,它返回一行在结果集中的位置。ROWNUM 在从数据库中选择记录之后和执行 ORDER 之前进行评估BY 子句。” 因此,它返回它认为在结果集中 #1 的任何行,在您的情况下将包含 1M 行。

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

于 2011-03-15T03:42:04.567 回答
0

我最近遇到了与您描述的相同的问题:我希望将非常大的表中的一行作为快速、肮脏、简单的内省,并且“where 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
于 2017-03-18T05:53:49.910 回答