2010-03-17 5 views
7

J'ai un peu de mal avec une sélection en insert sur un dblink dans l'oracle 10. J'utilise la déclaration suivante:Select et Insert dans dblink

INSERT INTO LOCAL.TABLE_1 (COL1, COL2) 
SELECT COL1, COL2 
FROM [email protected] s 
WHERE COL1 IN (SELECT COL1 FROM WORKING_TABLE) 

Quand je lance la déclaration qui suit est ce que obtient sur le serveur exécuter à distance sur le DB Link:

SELECT /*+ OPAQUE_TRANSFORM */ "COL1", "COL2" 
FROM "REMOTE"."TABLE1" "S" 

Si je lance la sélection uniquement et ne pas faire l'insert dans ce qui suit est exécuté:

SELECT /*+ */ "A1"."COL1" 
    , "A1"."COL2" 
    FROM "REMOTE"."TABLE1" "A1" 
WHERE "A1"."COL1" = 
    ANY (SELECT "A2"."COL1" 
     FROM "LOCAL"."TABLE1"@! "A2") 

Le problème est dans le cas d'insertion de la table d'enitre est tirée à travers le dblink, puis limité localy qui prend un peu de temps compte tenu de la taille de la table. Y a-t-il une raison pour laquelle ajouter l'insert changerait le comportement de cette manière?

Répondre

3

Vous pouvez utiliser l'indicateur driving_site. Il y a une bonne explication ici: http://www.dba-oracle.com/t_sql_dblink_performance.htm

+0

J'avais essayé d'ajouter l'indice suivant à la requête initiale avant de poster, mais j'ai obtenu les mêmes résultats. /* + DRIVING_SITE (s) */ Ce serait une allusion à conduire sur le côté dblink correct? – Domtar

2

Tirant parti de la clause WITH pourrait optimiser votre récupération de votre jeu de travail:

WITH remote_rows AS 
    (SELECT /*+DRIVING_SITE(s)*/COL1, COL2 
     FROM [email protected] s 
     WHERE COL1 IN (SELECT COL1 FROM WORKING_TABLE)) 
INSERT INTO LOCAL.TABLE_1 (COL1, COL2) 
SELECT COL1, COL2 
FROM remote_rows 
+0

[Cette réponse] (http://stackoverflow.com/questions/5885154/oracle-sql-insert-into-with-with-clause#5885845) montre que votre syntaxe ici n'est pas correcte. – Alfabravo

3

Quand il vient à DML, oracle choisit d'ignorer toute velléité de driving_site et exécute l'instruction sur le site cible. Je doute donc que vous puissiez changer cela (même en utilisant l'approche WITH décrite ci-dessus). Une solution de contournement possible est que vous pouvez créer un synonyme pour LOCAL.TABLE1 sur la base de données distante et utiliser la même chose dans votre instruction INSERT.

0

Quelle est la taille de WORKING_TABLE? Si elle est suffisamment petite, vous pouvez essayer de sélectionner work_table dans une collection, puis passer les éléments de cette collecte en tant qu'éléments dans une liste 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 [email protected] 
    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; 
/
+0

C'était mon approche initiale, mais il peut y avoir plus de 1000 éléments dans la table de travail. Je pense que je vais devoir interrompre le traitement par groupes de 1000 pour rester dans les limites. – Domtar

+0

Êtes-vous capable de créer une table temporaire globale sur le côté distant du lien? Vous pourriez insérer dans cela de la table de travail, alors la jointure serait tous sur le côté à distance. –

0

Insérer dans Zith indice de cardinalité semble fonctionner à 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 [email protected]_MIG_THALER CGD, 
        [email protected]_MIG_THALER ZFD, 
        EVD01_ADS_DR3W2 EVD 
1

Oracle ignore l'indice de driving_site pour les instructions d'insertion, comme DML est toujours exécutée localement. Pour ce faire, créez un curseur avec l'indicateur de site de conduite, puis faites une boucle sur le curseur avec bulkcollect/forall et insérez-le dans la table locale cible.