2

次のようなクエリを実行しようとしています

select * from tableName where rownum=1

このクエリは、基本的にテーブルの列名を取得することです。テーブルには100万件を超えるレコードがあります。上記の条件を設定すると、最初の行を取得するのに時間がかかります。最初の行を取得するための代替手段はありますか.

4

6 に答える 6

12

この質問はすでに回答済みです。フィルターROWNUM=1またはROWNUM<=1の場合に応答時間が長くなることがある理由について説明します。

(単一のテーブルで)ROWNUMフィルターに遭遇すると、オプティマイザーはCOUNTSTOPKEYを使用してフルスキャンを生成します。これは、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

sysibm.syscolumns確かに Oracle には、DB2のテーブルのように、列名を取得するために使用できるメタデータ テーブルがありますか?

そして、簡単な Web 検索の後、そのように見えます: を参照してくださいALL_TAB_COLUMNS

(未テスト) のような実際のテーブルに移動するのではなく、それらを使用します。

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

クエリが遅い理由を知りたがっている場合は、標準的な方法に戻る必要があります。つまり、DBMS にクエリの実行計画を説明してもらうことですOracle については、このドキュメントのセクション 9 を参照してください。

行番号が選択フェーズの後Ask Tom - Oracleに作成されることを示唆しているように見える会話があります。これは、とにかくクエリがすべての行を取得していることを意味する可能性があります。おそらくそれを確立するのに役立ちます。なしで含まれている場合、それがパフォーマンスを説明している可能性があります。explainFULLCOUNT STOPKEY

それを超えると、オラクルの詳細に関する私の知識が減少するため、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

Oracleのドキュメントによると、ROWNUMの概念が少し欠けていると思います。「ROWNUMは、結果セット内の行の位置を返す疑似列です。ROWNUMは、データベースからレコードが選択された後、ORDERの実行前に評価されます。 BY句。」 したがって、結果セットの#1と見なされる任意の行が返されます。この場合、100万行が含まれます。

ROWID疑似列を確認することをお勧めします:http://psoug.org/reference/pseudocols.html

于 2011-03-15T03:42:04.567 に答える
0

私は最近、あなたが説明しているのと同じ問題を抱えていました.非常に大きなテーブルから1行を素早く、汚い、単純なイントロスペクションとして欲しいのですが、「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 に答える