2016-10-17 4 views
2

で高速検索コレクション型を作成します。コレクション型の列

CREATE TYPE nums_list AS TABLE OF NUMBER; 

は、コレクション型(ネストした表の列)の列を持つ表を作成します。テーブル内の

CREATE TABLE test1 (
     num NUMBER, 
     tagged nums_list 
) 
NESTED TABLE tagged STORE AS mytest_tagged_table; 

挿入1万行:

DECLARE 
    tagg_value nums_list := nums_list(3,4,5); 
BEGIN 
    for i in 1..1000000 loop 
      if i = 600000 then 
       tagg_value := nums_list(7,8); 
      end if; 

      INSERT INTO test1 
      (num, tagged) 
      VALUES 
      (i, tagg_value); 
    end loop; 
END; 

次に、コレクションタイプの要素を検索するためにクエリを実行します。

select count(*) from test1 where 8 member of tagged; 

このクエリは、実行時間が約7-8秒であり、ゆっくり実行されます。

質問:実行時間を短縮する方法を教えてください。インデックスかもしれない?しかし、どのようにネストしたテーブルの列のためのインデックスを使用する私は取得できません。

P.S.私は、カーソルを使用してPL/SQLブロック内のすべての行をチェックし、パイプライン化されたテーブル関数として結果を返すことを試みましたが、これは直接クエリよりも遅かったです。

+0

あなたの例を書いたように、600,000以上のすべての行はリスト内の数字が8になると思います。つまり、クエリは400,000(1,000,000行のうち)を返します。ネストされたテーブルかどうかは、インデックスが役立つクエリのタイプではありません。この例ではあなたの意図は、クエリを満足する多くの行を持つことでしたか? –

+1

@Matthew - 正確に400,001 rowsがこのクエリを返します。これは大きなデータですか? – RIKI

+1

それはそれ自体が「大きな」ものではありません。テーブルの行の総数のうち大きな割合を占めています。そのような状況では、400,000回の索引検索ではなく、検索を実行するためにテーブル全体(すなわち、「全テーブルスキャン」)を読む方がより効率的である。1回のI/Oでフルスキャンで多くのテーブルブロックを読み取ることができますが、インデックスルックアップでは3〜4回の入出力が必要です。このような狭いテーブルでは、フル・テーブル・スキャンで100,000回のI/O(大まかな推測)を必要とする場合がありますが、索引付きのネストループ・ジョインは100万回以上のI/Oを必要とする場合があります。 –

答えて

3

あなたはあなたの例から、このクエリにEXPLAIN PLANを実行する場合:

select count(*) from test1 where 8 member of tagged; 

...あなたは、Oracleは、おそらくがパフォーマンスを助けるためにmytest_tagged_tableに(システム生成の)インデックスを使用してであることがわかります。それでも時間がかかりすぎる理由は、テーブル全体を読むだけでは、実際にはよりも少ない未満の400,000回のインデックスルックアップが効率的です。

「Oracleにネストした表で索引を使用させるにはどうすればよいですか」という質問はありません。それはどうすればにすることができますか?

あなたのtaggedリストが小さいように見えるので、1つの代替方法はVARRAYです。関連する構文はきれいではありませんが、これらはパフォーマンス向上のためにインラインで格納できます。ここで

VARRAYのために変更あなたの例です:

私のシステムで
CREATE NONEDITIONABLE TYPE nums_varray AS VARRAY(10) OF NUMBER; 

CREATE TABLE test2 (
     num NUMBER, 
     tagged nums_varray 
); 

INSERT INTO test2 
SELECT rownum, 
     case when rownum < 600000 then new nums_varray(3,4,5) else new nums_varray(7,8) end 
FROM dual 
connect by rownum <= 1000000; 


select count(*) from test2 
where exists ( 
    SELECT '8 in list' 
    FROM TABLE(tagged) 
    WHERE column_value = 8); 

、これに必要な唯一の3600バッファが実行するようになる - 2.1 バッファとは対照的に、あなたの例のクエリが必要なことを取得します。これに対応して、これもはるかに高速に動作します。

VARRAYSは、ネストした表と直接同等ではなく、警告が付いています。しかし、あなたの例に基づいて、あなたが探しているものかもしれません。

関連する問題