Oracle10のdblinkでのselectintoinsertに少し問題があります。次のステートメントを使用しています。
INSERT INTO LOCAL.TABLE_1 ( COL1, COL2)
SELECT COL1, COL2
FROM REMOTE.TABLE1@dblink s
WHERE COL1 IN ( SELECT COL1 FROM WORKING_TABLE)
ステートメントを実行すると、DBリンク上のリモートサーバーに対して実行されるのは次のとおりです。
SELECT /*+ OPAQUE_TRANSFORM */ "COL1", "COL2"
FROM "REMOTE"."TABLE1" "S"
選択のみを実行し、挿入を実行しない場合、以下が実行されます。
SELECT /*+ */ "A1"."COL1"
, "A1"."COL2"
FROM "REMOTE"."TABLE1" "A1"
WHERE "A1"."COL1" =
ANY ( SELECT "A2"."COL1"
FROM "LOCAL"."TABLE1"@! "A2")
問題は、挿入の場合、全体のテーブルがdblinkを介してプルされ、ローカルが制限されることです。これには、テーブルのサイズを考えるとかなりの時間がかかります。インサートを追加すると、このように動作が変わる理由はありますか?
Driving_siteヒントを使用することをお勧めします。ここに良い説明があります: http://www.dba-Oracle.com/t_sql_dblink_performance.htm
DMLに関しては、Oracleはdriving_siteヒントを無視することを選択し、ターゲットサイトでステートメントを実行します。したがって、(上記のWITHアプローチを使用しても)それを変更できるかどうかは疑問です。考えられる回避策は、リモートデータベースにLOCAL.TABLE1のシノニムを作成し、それをINSERTステートメントで使用することです。
WITH句を利用すると、ワーキングセットの取得を最適化できます。
WITH remote_rows AS
(SELECT /*+DRIVING_SITE(s)*/COL1, COL2
FROM REMOTE.TABLE1@dblink s
WHERE COL1 IN ( SELECT COL1 FROM WORKING_TABLE))
INSERT INTO LOCAL.TABLE_1 ( COL1, COL2)
SELECT COL1, COL2
FROM remote_rows
DMLは常にローカルで実行されるため、Oracleは挿入ステートメントのdriving_siteヒントを無視します。これを行う方法は、駆動サイトのヒントを使用してカーソルを作成し、bulkcollect/forallを使用してカーソルをループし、ターゲットのローカルテーブルに挿入することです。
WORKING_TABLEの大きさはどれくらいですか?十分に小さい場合は、work_tableからコレクションに選択してから、そのコレクションの要素をINリストの要素として渡すことができます。
declare
TYPE t_type IS TABLE OF VARCHAR2(60);
v_coll t_type;
begin
dbms_application_info.set_module('TEST','TEST');
--
select distinct object_type
bulk collect into v_coll
from user_objects;
--
IF v_coll.count > 20 THEN
raise_application_error(-20001,'You need '||v_coll.count||' elements in the IN list');
ELSE
v_coll.extend(20);
END IF;
insert into abc (object_type, object_name)
select object_type, object_name
from user_objects@tmfprd
where object_type in
(v_coll(1), v_coll(2), v_coll(3), v_coll(4), v_coll(5),
v_coll(6), v_coll(7), v_coll(8), v_coll(9), v_coll(10),
v_coll(11), v_coll(12), v_coll(13), v_coll(14), v_coll(15),
v_coll(16), v_coll(17), v_coll(18), v_coll(19), v_coll(20)
);
--
dbms_output.put_line(sql%rowcount);
end;
/
カーディナリティヒントを使用した挿入は11.2で機能するようです
INSERT /*+ append */
INTO MIG_CGD30_TEST
SELECT /*+ cardinality(ZFD 400000) cardinality(CGD 60000000)*/
TRIM (CGD.NUMCPT) AS NUMCPT, TRIM (ZFD.NUMBDC_NEW) AS NUMBDC
FROM CGD30@DBL_MIG_THALER CGD,
ZFD10@DBL_MIG_THALER ZFD,
EVD01_ADS_DR3W2 EVD