2009-07-02 8 views
6

これは、同じサブクエリを使用する3つの異なる選択です。サブクエリを実行する代わりにサブクエリの結果を使用する方法複数のoracleで同じサブクエリを避けるにはどうすればよいですか?

SELECT * 
FROM Address 
WHERE address_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); -- person_list := '1,2,3,4' 

SELECT * 
FROM Phone 
WHERE phone_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); 

SELECT * 
FROM Email 
WHERE address_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); 

答えて

6

あなたはこのクエリのマテリアライズド・ビューを作成することができます

CREATE MATERIALIZED VIEW v_address 
REFRESH FORCE ON COMMIT 
AS 
SELECT address_key 
FROM person_address 
WHERE person_key IN (person_list) 

を、または一時テーブルを作成し、それを移入:、本当に、

CREATE GLOBAL TEMPORARY TABLE tt_address (VARCHAR2(50)); 

INSERT 
INTO tt_address 
SELECT address_key 
FROM person_address 
WHERE person_key IN (person_list) 

が、あなたのインデックスであれば、あなたのperson_key、サブクエリを再利用しても問題ありません。

別々のクエリ3があるため、値を一方向に表示する必要があります。

つまり、これらの値は、メモリー、一時表領域、永続表領域のいずれかに格納する必要があります。

ただし、必要な値はすでにperson_addressに保存されています。必要なのはフェッチするだけです。サブクエリ3回を使用して

がテーブルからaddress_keyをフェッチするperson_key12テーブルの上にインデックスからROWID検索をROWID年代をフェッチするために12インデックススキャンを必要とするだろう。次に、おそらくHASH TABLEがそれらの上に構築されます。

これはマイクロ秒です。

もちろん、テンポラリ・テーブルまたはマテリアライズド・ビューはもう少し効率的ですが、副問合せ時間を100マイクロ秒から50に変更することは、メイン問合せに数分かかることはほとんどありません。

+0

+1またはGTTの考え方 - 特に、ここに入力するロジックがここの例より複雑で時間がかかる場合。 –

6

with句を使用します。私はあなたの正確なサンプルの問題を再作成しませんでしたが、何回でも繰り返されるサブクエリをWITH節に入れてからクエリで参照することができます。

WITH address_keys as (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ) 
Select * from table1, table2, address_keys 
where table1.address_key = address_keys.address_key 
and table2.address_key = address_keys.address_key 
+0

Withは、私が望むように3つの結果セットを返しません。 WITH句で作成されたビューは、複数のクエリではなく1つのクエリでのみ使用できます。私は何かが足りないかもしれない。 –

+0

ブライアンのポイントは、3つのクエリを実行しないことです.1つのクエリをUNION ALLで実行することです。この方法も効率的になるでしょう。 –

+0

もちろん、3つの結果セットが大きく違うパターンを持っている場合は、おそらくこれは役に立ちません:) –

4

まず私は、ほとんどの場合、この最適化は重要な改善を(最初のクエリの後PERSON_ADDRESSのデータ・ブロックは、主にバッファ・キャッシュにキャッシュされることになるので、HDDから読み込まれていない)持っていないと思います。

ただし、ケーススタディまたは何らかの理由で: 繰り返しクエリ結果をキャッシュし、後で3つの選択肢に再利用する必要があります。これは、(temp)表またはMVまたはplsql構造のVARRAYによって実現できます。

最初の2つのオプションはQuassnoiの答えですので、私は言及しません。 3番目の方法は、行の最大数を前もって指定しなければならないという欠点があります(1kだけ必要な場合でも1Mまたは1G項目の上限があるVARRAYを宣言すると何が起こるかわからない)。

--creating db object to hold the data - maximum of 1000 items allowed. 
--I assume that key is number(10,0). 
create type t_address_keys is varray (1000) of number (10,0); 

declare 
    la_address_keys t_address_keys; --declare cache variable 
begin 

--cache keys 
SELECT address_key 
bulk collect into la_address_keys 
     FROM person_address 
     WHERE peson_key IN (person_list); 

SELECT * 
into ... 
FROM Address 
WHERE address_key IN table(la_address_keys); 

SELECT * 
into ... 
FROM Phone 
WHERE address_key IN table(la_address_keys); 

SELECT * 
into ... 
FROM email 
WHERE address_key IN table(la_address_keys); 

end; 
/
関連する問題